|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Kivy typing completer. |
|
8 """ |
|
9 |
|
10 import re |
|
11 |
|
12 from PyQt6.Qsci import QsciScintilla |
|
13 |
|
14 from eric7.QScintilla.TypingCompleters.CompleterBase import CompleterBase |
|
15 |
|
16 |
|
17 class CompleterKivy(CompleterBase): |
|
18 """ |
|
19 Class implementing the Kivy typing completer. |
|
20 """ |
|
21 |
|
22 def __init__(self, plugin, editor, parent=None): |
|
23 """ |
|
24 Constructor |
|
25 |
|
26 @param plugin reference to the plugin object |
|
27 @type ProjectKivyPlugin |
|
28 @param editor reference to the editor object |
|
29 @type Editor |
|
30 @param parent reference to the parent object |
|
31 @type QObject |
|
32 """ |
|
33 super().__init__(editor, parent) |
|
34 |
|
35 self.__plugin = plugin |
|
36 |
|
37 self.__autoIndentationRe = re.compile(r"(?:\(|\[|{|:)(\s*)\r?\n") |
|
38 |
|
39 self.readSettings() |
|
40 |
|
41 def readSettings(self): |
|
42 """ |
|
43 Public slot called to reread the configuration parameters. |
|
44 """ |
|
45 self.setEnabled(self.__plugin.getTypingPreferences("EnabledTypingAids")) |
|
46 self.__insertClosingBrace = self.__plugin.getTypingPreferences( |
|
47 "InsertClosingBrace" |
|
48 ) |
|
49 self.__skipBrace = self.__plugin.getTypingPreferences("SkipBrace") |
|
50 self.__colonDetection = self.__plugin.getTypingPreferences("ColonDetection") |
|
51 self.__autoIndentation = self.__plugin.getTypingPreferences("AutoIndentation") |
|
52 self.__insertQuote = self.__plugin.getTypingPreferences("InsertQuote") |
|
53 self.__insertBlankColon = self.__plugin.getTypingPreferences("InsertBlankColon") |
|
54 self.__insertBlankComma = self.__plugin.getTypingPreferences("InsertBlankComma") |
|
55 |
|
56 def charAdded(self, charNumber): |
|
57 """ |
|
58 Public slot called to handle the user entering a character. |
|
59 |
|
60 @param charNumber value of the character entered |
|
61 @type int |
|
62 """ |
|
63 char = chr(charNumber) |
|
64 if char not in ( |
|
65 "{", |
|
66 "}", |
|
67 "[", |
|
68 "]", |
|
69 "(", |
|
70 ")", |
|
71 "<", |
|
72 ">", |
|
73 "'", |
|
74 '"', |
|
75 ":", |
|
76 ",", |
|
77 "\n", |
|
78 ): |
|
79 return # take the short route |
|
80 |
|
81 line, col = self.editor.getCursorPosition() |
|
82 |
|
83 if self.__inComment(line, col): |
|
84 return |
|
85 |
|
86 # open parenthesis |
|
87 # insert closing parenthesis |
|
88 if char == "(" and self.__insertClosingBrace: |
|
89 self.editor.insert(")") |
|
90 |
|
91 # open curly bracket |
|
92 # insert closing bracket |
|
93 elif char == "{" and self.__insertClosingBrace: |
|
94 self.editor.insert("}") |
|
95 |
|
96 # open bracket |
|
97 # insert closing bracket |
|
98 elif char == "[" and self.__insertClosingBrace: |
|
99 self.editor.insert("]") |
|
100 |
|
101 # open tag bracket |
|
102 # insert closing bracket |
|
103 elif char == "<" and self.__insertClosingBrace: |
|
104 self.editor.insert(">") |
|
105 |
|
106 # closing parenthesis |
|
107 # skip matching closing parenthesis |
|
108 elif char in (")", "}", "]", ">"): |
|
109 txt = self.editor.text(line) |
|
110 if col < len(txt) and char == txt[col] and self.__skipBrace: |
|
111 self.editor.setSelection(line, col, line, col + 1) |
|
112 self.editor.removeSelectedText() |
|
113 |
|
114 # colon |
|
115 # 1. skip colon if not last character |
|
116 # 2. insert blank if last character |
|
117 elif char == ":": |
|
118 text = self.editor.text(line) |
|
119 if col < len(text) and char == text[col]: |
|
120 if self.__colonDetection: |
|
121 self.editor.setSelection(line, col, line, col + 1) |
|
122 self.editor.removeSelectedText() |
|
123 elif self.__insertBlankColon and col == len(text.rstrip()): |
|
124 self.editor.insert(" ") |
|
125 self.editor.setCursorPosition(line, col + 1) |
|
126 |
|
127 # comma |
|
128 # insert blank |
|
129 elif char == "," and self.__insertBlankComma: |
|
130 self.editor.insert(" ") |
|
131 self.editor.setCursorPosition(line, col + 1) |
|
132 |
|
133 # double quote |
|
134 # insert double quote |
|
135 elif char == '"' and self.__insertQuote: |
|
136 self.editor.insert('"') |
|
137 |
|
138 # quote |
|
139 # insert quote |
|
140 elif char == "'" and self.__insertQuote: |
|
141 self.editor.insert("'") |
|
142 |
|
143 # new line |
|
144 # indent after line ending with ':' |
|
145 elif char == "\n" and self.__autoIndentation: |
|
146 txt = self.editor.text(line - 1) |
|
147 match = self.__autoIndentationRe.search(txt) |
|
148 if match is not None: |
|
149 startBlanks = match.start(1) |
|
150 endBlanks = match.end(1) |
|
151 if startBlanks != -1 and startBlanks != endBlanks: |
|
152 # previous line ends with whitespace, e.g. caused by |
|
153 # blank insertion above |
|
154 self.editor.setSelection(line - 1, startBlanks, line - 1, endBlanks) |
|
155 self.editor.removeSelectedText() |
|
156 |
|
157 self.editor.indent(line) |
|
158 self.editor.setCursorPosition(line, 0) |
|
159 self.editor.editorCommand(QsciScintilla.SCI_VCHOME) |
|
160 |
|
161 def __inComment(self, line, col): |
|
162 """ |
|
163 Private method to check, if the cursor is inside a comment. |
|
164 |
|
165 @param line current line |
|
166 @type int |
|
167 @param col current position within line |
|
168 @type int |
|
169 @return flag indicating, if the cursor is inside a comment |
|
170 @rtype bool |
|
171 """ |
|
172 txt = self.editor.text(line) |
|
173 if col == len(txt): |
|
174 col -= 1 |
|
175 while col >= 0: |
|
176 if txt[col] == "#": |
|
177 return True |
|
178 col -= 1 |
|
179 return False |