src/eric7/QScintilla/TypingCompleters/CompleterRuby.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a typing completer for Ruby.
8 """
9
10 import re
11
12 from PyQt6.Qsci import QsciLexerRuby, QsciScintilla
13
14 from .CompleterBase import CompleterBase
15
16 import Preferences
17
18
19 class CompleterRuby(CompleterBase):
20 """
21 Class implementing typing completer for Ruby.
22 """
23 def __init__(self, editor, parent=None):
24 """
25 Constructor
26
27 @param editor reference to the editor object (QScintilla.Editor)
28 @param parent reference to the parent object (QObject)
29 """
30 super().__init__(editor, parent)
31
32 self.__beginRX = re.compile(r"""^=begin """)
33 self.__beginNlRX = re.compile(r"""^=begin\r?\n""")
34 self.__hereRX = re.compile(r"""<<-?['"]?(\w*)['"]?\r?\n""")
35
36 self.readSettings()
37
38 def readSettings(self):
39 """
40 Public slot called to reread the configuration parameters.
41 """
42 self.setEnabled(Preferences.getEditorTyping("Ruby/EnabledTypingAids"))
43 self.__insertClosingBrace = Preferences.getEditorTyping(
44 "Ruby/InsertClosingBrace")
45 self.__indentBrace = Preferences.getEditorTyping(
46 "Ruby/IndentBrace")
47 self.__skipBrace = Preferences.getEditorTyping(
48 "Ruby/SkipBrace")
49 self.__insertQuote = Preferences.getEditorTyping(
50 "Ruby/InsertQuote")
51 self.__insertBlank = Preferences.getEditorTyping(
52 "Ruby/InsertBlank")
53 self.__insertHereDoc = Preferences.getEditorTyping(
54 "Ruby/InsertHereDoc")
55 self.__insertInlineDoc = Preferences.getEditorTyping(
56 "Ruby/InsertInlineDoc")
57
58 def charAdded(self, charNumber):
59 """
60 Public slot called to handle the user entering a character.
61
62 @param charNumber value of the character entered (integer)
63 """
64 char = chr(charNumber)
65 if char not in ['(', ')', '{', '}', '[', ']', ',', "'", '"',
66 '\n', ' ']:
67 return # take the short route
68
69 line, col = self.editor.getCursorPosition()
70
71 if (
72 self.__inComment(line, col) or
73 self.__inDoubleQuotedString() or
74 self.__inSingleQuotedString() or
75 self.__inHereDocument() or
76 self.__inInlineDocument()
77 ):
78 return
79
80 # open parenthesis
81 # insert closing parenthesis and self
82 if char == '(':
83 txt = self.editor.text(line)[:col]
84 if self.__insertClosingBrace:
85 self.editor.insert(')')
86
87 # closing parenthesis
88 # skip matching closing parenthesis
89 elif char in [')', '}', ']']:
90 txt = self.editor.text(line)
91 if col < len(txt) and char == txt[col] and self.__skipBrace:
92 self.editor.setSelection(line, col, line, col + 1)
93 self.editor.removeSelectedText()
94
95 # space
96 # complete inline documentation
97 elif char == ' ':
98 txt = self.editor.text(line)[:col]
99 if self.__insertInlineDoc and self.__beginRX.fullmatch(txt):
100 self.editor.insert('=end')
101
102 # comma
103 # insert blank
104 elif char == ',' and self.__insertBlank:
105 self.editor.insert(' ')
106 self.editor.setCursorPosition(line, col + 1)
107
108 # open curly brace
109 # insert closing brace
110 elif char == '{' and self.__insertClosingBrace:
111 self.editor.insert('}')
112
113 # open bracket
114 # insert closing bracket
115 elif char == '[' and self.__insertClosingBrace:
116 self.editor.insert(']')
117
118 # double quote
119 # insert double quote
120 elif char == '"' and self.__insertQuote:
121 self.editor.insert('"')
122
123 # quote
124 # insert quote
125 elif char == '\'' and self.__insertQuote:
126 self.editor.insert('\'')
127
128 # new line
129 # indent to opening brace, complete inline documentation
130 elif char == '\n':
131 txt = self.editor.text(line - 1)
132 if self.__insertInlineDoc and self.__beginNlRX.fullmatch(txt):
133 self.editor.insert('=end')
134 elif self.__insertHereDoc and self.__hereRX.fullmatch(txt):
135 self.editor.insert(self.__hereRX.fullmatch(txt).group(1))
136 elif self.__indentBrace and re.search(":\r?\n", txt) is None:
137 stxt = txt.strip()
138 if stxt and stxt[-1] in ("(", "[", "{"):
139 # indent one more level
140 self.editor.indent(line)
141 self.editor.editorCommand(QsciScintilla.SCI_VCHOME)
142 else:
143 # indent to the level of the opening brace
144 openCount = len(re.findall("[({[]", txt))
145 closeCount = len(re.findall(r"[)}\]]", txt))
146 if openCount > closeCount:
147 openCount = 0
148 closeCount = 0
149 openList = list(re.finditer("[({[]", txt))
150 index = len(openList) - 1
151 while index > -1 and openCount == closeCount:
152 lastOpenIndex = openList[index].start()
153 txt2 = txt[lastOpenIndex:]
154 openCount = len(re.findall("[({[]", txt2))
155 closeCount = len(re.findall(r"[)}\]]", txt2))
156 index -= 1
157 if openCount > closeCount and lastOpenIndex > col:
158 self.editor.insert(' ' * (lastOpenIndex - col + 1))
159 self.editor.setCursorPosition(line,
160 lastOpenIndex + 1)
161
162 def __inComment(self, line, col):
163 """
164 Private method to check, if the cursor is inside a comment.
165
166 @param line current line (integer)
167 @param col current position within line (integer)
168 @return flag indicating, if the cursor is inside a comment (boolean)
169 """
170 txt = self.editor.text(line)
171 if col == len(txt):
172 col -= 1
173 while col >= 0:
174 if txt[col] == "#":
175 return True
176 col -= 1
177 return False
178
179 def __inDoubleQuotedString(self):
180 """
181 Private method to check, if the cursor is within a double quoted
182 string.
183
184 @return flag indicating, if the cursor is inside a double
185 quoted string (boolean)
186 """
187 return self.editor.currentStyle() == QsciLexerRuby.DoubleQuotedString
188
189 def __inSingleQuotedString(self):
190 """
191 Private method to check, if the cursor is within a single quoted
192 string.
193
194 @return flag indicating, if the cursor is inside a single
195 quoted string (boolean)
196 """
197 return self.editor.currentStyle() == QsciLexerRuby.SingleQuotedString
198
199 def __inHereDocument(self):
200 """
201 Private method to check, if the cursor is within a here document.
202
203 @return flag indicating, if the cursor is inside a here document
204 (boolean)
205 """
206 return self.editor.currentStyle() == QsciLexerRuby.HereDocument
207
208 def __inInlineDocument(self):
209 """
210 Private method to check, if the cursor is within an inline document.
211
212 @return flag indicating, if the cursor is inside an inline document
213 (boolean)
214 """
215 return self.editor.currentStyle() == QsciLexerRuby.POD

eric ide

mercurial