18 |
18 |
19 from PyQt4.QtCore import * |
19 from PyQt4.QtCore import * |
20 |
20 |
21 import Preferences |
21 import Preferences |
22 import Utilities |
22 import Utilities |
|
23 |
23 |
24 |
24 class SpellChecker(QObject): |
25 class SpellChecker(QObject): |
25 """ |
26 """ |
26 Class implementing a pyenchant based spell checker. |
27 Class implementing a pyenchant based spell checker. |
27 """ |
28 """ |
28 # class attributes to be used as defaults |
29 # class attributes to be used as defaults |
29 _spelling_lang = None |
30 _spelling_lang = None |
30 _spelling_dict = None |
31 _spelling_dict = None |
31 |
32 |
32 def __init__(self, editor, indicator, defaultLanguage = None, checkRegion = None): |
33 def __init__(self, editor, indicator, defaultLanguage=None, checkRegion=None): |
33 """ |
34 """ |
34 Constructor |
35 Constructor |
35 |
36 |
36 @param editor reference to the editor object (QScintilla.Editor) |
37 @param editor reference to the editor object (QScintilla.Editor) |
37 @param indicator spell checking indicator |
38 @param indicator spell checking indicator |
81 except NameError: |
82 except NameError: |
82 pass |
83 pass |
83 return False |
84 return False |
84 |
85 |
85 @classmethod |
86 @classmethod |
86 def _getDict(cls, lang, pwl = "", pel = ""): |
87 def _getDict(cls, lang, pwl="", pel=""): |
87 """ |
88 """ |
88 Protected classmethod to get a new dictionary. |
89 Protected classmethod to get a new dictionary. |
89 |
90 |
90 @param lang the language to be used as the default (string). |
91 @param lang the language to be used as the default (string). |
91 The string should be in language locale format (e.g. en_US, de). |
92 The string should be in language locale format (e.g. en_US, de). |
126 The string should be in language locale format (e.g. en_US, de). |
127 The string should be in language locale format (e.g. en_US, de). |
127 """ |
128 """ |
128 cls._spelling_lang = language |
129 cls._spelling_lang = language |
129 cls._spelling_dict = cls._getDict(language) |
130 cls._spelling_dict = cls._getDict(language) |
130 |
131 |
131 def setLanguage(self, language, pwl = "", pel = ""): |
132 def setLanguage(self, language, pwl="", pel=""): |
132 """ |
133 """ |
133 Public method to set the current language. |
134 Public method to set the current language. |
134 |
135 |
135 @param language the language to be used as the default (string). |
136 @param language the language to be used as the default (string). |
136 The string should be in language locale format (e.g. en_US, de). |
137 The string should be in language locale format (e.g. en_US, de). |
137 @keyparam pwl name of the personal/project word list (string) |
138 @keyparam pwl name of the personal/project word list (string) |
138 @keyparam pel name of the personal/project exclude list (string) |
139 @keyparam pel name of the personal/project exclude list (string) |
139 """ |
140 """ |
140 self._spelling_lang = language |
141 self._spelling_lang = language |
141 self._spelling_dict = self._getDict(language, pwl = pwl, |
142 self._spelling_dict = self._getDict(language, pwl=pwl, |
142 pel = pel) |
143 pel=pel) |
143 |
144 |
144 def getLanguage(self): |
145 def getLanguage(self): |
145 """ |
146 """ |
146 Public method to get the current language. |
147 Public method to get the current language. |
147 |
148 |
161 """ |
162 """ |
162 Private method to get the next word in the text after the given position. |
163 Private method to get the next word in the text after the given position. |
163 |
164 |
164 @param pos position to start word extraction (integer) |
165 @param pos position to start word extraction (integer) |
165 @param endPosition position to stop word extraction (integer) |
166 @param endPosition position to stop word extraction (integer) |
166 @return tuple of three values (the extracted word (string), |
167 @return tuple of three values (the extracted word (string), |
167 start position (integer), end position (integer)) |
168 start position (integer), end position (integer)) |
168 """ |
169 """ |
169 if pos < 0 or pos >= endPosition: |
170 if pos < 0 or pos >= endPosition: |
170 return "", -1, -1 |
171 return "", -1, -1 |
171 |
172 |
173 # 1. skip non-word characters |
174 # 1. skip non-word characters |
174 while pos < endPosition and not ch.isalnum(): |
175 while pos < endPosition and not ch.isalnum(): |
175 pos = self.editor.positionAfter(pos) |
176 pos = self.editor.positionAfter(pos) |
176 ch = self.editor.charAt(pos) |
177 ch = self.editor.charAt(pos) |
177 if pos == endPosition: |
178 if pos == endPosition: |
178 return "", -1, -1 |
179 return "", -1, -1 |
179 startPos = pos |
180 startPos = pos |
180 |
181 |
181 # 2. extract the word |
182 # 2. extract the word |
182 word = "" |
183 word = "" |
183 while pos < endPosition and ch.isalnum(): |
184 while pos < endPosition and ch.isalnum(): |
267 if self.lastCheckedLine >= self.editor.lines(): |
268 if self.lastCheckedLine >= self.editor.lines(): |
268 self.lastCheckedLine = -1 |
269 self.lastCheckedLine = -1 |
269 else: |
270 else: |
270 QTimer.singleShot(0, self.__incrementalCheck) |
271 QTimer.singleShot(0, self.__incrementalCheck) |
271 |
272 |
272 def checkWord(self, pos, atEnd = False): |
273 def checkWord(self, pos, atEnd=False): |
273 """ |
274 """ |
274 Public method to check the word at position pos. |
275 Public method to check the word at position pos. |
275 |
276 |
276 @param pos position to check at (integer) |
277 @param pos position to check at (integer) |
277 @keyparam atEnd flag indicating the position is at the end of the word |
278 @keyparam atEnd flag indicating the position is at the end of the word |
294 pos0 = self.editor.positionBefore(pos) |
295 pos0 = self.editor.positionBefore(pos) |
295 |
296 |
296 for pos in [pos0, pos1]: |
297 for pos in [pos0, pos1]: |
297 if self.editor.charAt(pos).isalnum(): |
298 if self.editor.charAt(pos).isalnum(): |
298 line, index = self.editor.lineIndexFromPosition(pos) |
299 line, index = self.editor.lineIndexFromPosition(pos) |
299 word = self.editor.getWord(line, index, useWordChars = False) |
300 word = self.editor.getWord(line, index, useWordChars=False) |
300 if len(word) >= self.minimumWordSize: |
301 if len(word) >= self.minimumWordSize: |
301 ok = spell.check(word) |
302 ok = spell.check(word) |
302 else: |
303 else: |
303 ok = True |
304 ok = True |
304 start, end = \ |
305 start, end = \ |
305 self.editor.getWordBoundaries(line, index, useWordChars = False) |
306 self.editor.getWordBoundaries(line, index, useWordChars=False) |
306 if ok: |
307 if ok: |
307 self.editor.clearIndicator(self.indicator, line, start, line, end) |
308 self.editor.clearIndicator(self.indicator, line, start, line, end) |
308 else: |
309 else: |
309 # spell check indicated an error |
310 # spell check indicated an error |
310 self.editor.setIndicator(self.indicator, line, start, line, end) |
311 self.editor.setIndicator(self.indicator, line, start, line, end) |
353 Private method to check the current selection. |
354 Private method to check the current selection. |
354 """ |
355 """ |
355 selStartLine, selStartIndex, selEndLine, selEndIndex = \ |
356 selStartLine, selStartIndex, selEndLine, selEndIndex = \ |
356 self.editor.getSelection() |
357 self.editor.getSelection() |
357 self.__checkDocumentPart( |
358 self.__checkDocumentPart( |
358 self.editor.positionFromLineIndex(selStartLine, selStartIndex), |
359 self.editor.positionFromLineIndex(selStartLine, selStartIndex), |
359 self.editor.positionFromLineIndex(selEndLine, selEndIndex) |
360 self.editor.positionFromLineIndex(selEndLine, selEndIndex) |
360 ) |
361 ) |
361 |
362 |
362 def checkCurrentPage(self): |
363 def checkCurrentPage(self): |
363 """ |
364 """ |
407 """ |
408 """ |
408 spell = self._spelling_dict |
409 spell = self._spelling_dict |
409 if spell: |
410 if spell: |
410 spell.remove(word) |
411 spell.remove(word) |
411 |
412 |
412 def ignoreAlways(self, word = None): |
413 def ignoreAlways(self, word=None): |
413 """ |
414 """ |
414 Public method to tell the checker, to always ignore the given word |
415 Public method to tell the checker, to always ignore the given word |
415 or the current word. |
416 or the current word. |
416 |
417 |
417 @param word word to be ignored (string) |
418 @param word word to be ignored (string) |
421 if word not in self.__ignoreWords: |
422 if word not in self.__ignoreWords: |
422 self.__ignoreWords.append(word) |
423 self.__ignoreWords.append(word) |
423 |
424 |
424 def replace(self, replacement): |
425 def replace(self, replacement): |
425 """ |
426 """ |
426 Public method to tell the checker to replace the current word with |
427 Public method to tell the checker to replace the current word with |
427 the replacement string. |
428 the replacement string. |
428 |
429 |
429 @param replacement replacement string (string) |
430 @param replacement replacement string (string) |
430 """ |
431 """ |
431 sline, sindex = self.editor.lineIndexFromPosition(self.wordStart) |
432 sline, sindex = self.editor.lineIndexFromPosition(self.wordStart) |