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