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