From f4accab93fe02ffbf69ba8395d2f8e71396471f2 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 7 Nov 2019 22:05:03 +0100 Subject: [PATCH] Spell checking tools and project word lists now cooperate --- nw/config.py | 1 + nw/tools/spellcheck.py | 34 +++++++++++++++++++++++++++++++ nw/tools/spellenchant.py | 19 +++++++++-------- nw/tools/spellsimple.py | 44 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/nw/config.py b/nw/config.py index 42c11bcb..7047354b 100644 --- a/nw/config.py +++ b/nw/config.py @@ -90,6 +90,7 @@ class Config: self.showTabsNSpaces = False self.showLineEndings = False + self.fmtApostrophe = nwUnicode.U_RSQUO self.fmtSingleQuotes = [nwUnicode.U_LSQUO,nwUnicode.U_RSQUO] self.fmtDoubleQuotes = [nwUnicode.U_LDQUO,nwUnicode.U_RDQUO] diff --git a/nw/tools/spellcheck.py b/nw/tools/spellcheck.py index 7d5575e1..94227b29 100644 --- a/nw/tools/spellcheck.py +++ b/nw/tools/spellcheck.py @@ -22,8 +22,11 @@ class NWSpellCheck(): SP_SYMSPELL = "symspell" theDict = None + PROJW = [] def __init__(self): + self.mainConf = nw.CONFIG + self.projectDict = None return def setLanguage(self, theLang, projectDict=None): @@ -36,9 +39,40 @@ class NWSpellCheck(): return [] def addWord(self, newWord): + if self.projectDict is not None and newWord not in self.PROJW: + newWord = newWord.strip() + self.PROJW.append(newWord) + try: + with open(self.projectDict,mode="w+",encoding="utf-8") as outFile: + for pWord in self.PROJW: + outFile.write("%s\n" % pWord) + except Exception as e: + logger.error("Failed to write to project word list at %s" % str(self.projectDict)) + logger.error(str(e)) return def listDictionaries(self): return [] + ## + # Internal Functions + ## + + def _readProjectDictionary(self, projectDict): + self.PROJW = [] + if projectDict is not None: + self.projectDict = projectDict + try: + with open(projectDict,mode="r",encoding="utf-8") as wordsFile: + for theLine in wordsFile: + theLine = theLine.strip() + if len(theLine) > 0 and theLine not in self.PROJW: + self.PROJW.append(theLine) + logger.debug("Project word list") + logger.debug("Project word list contains %d words" % len(self.PROJW)) + except Exception as e: + logger.error("Failed to load project word list") + logger.error(str(e)) + return + # END Class NWSpellCheck diff --git a/nw/tools/spellenchant.py b/nw/tools/spellenchant.py index a37949c1..e4116580 100644 --- a/nw/tools/spellenchant.py +++ b/nw/tools/spellenchant.py @@ -32,15 +32,16 @@ class NWSpellEnchant(NWSpellCheck): crash. """ try: - if projectDict is None: - self.theDict = enchant.Dict(theLang) - else: - self.theDict = enchant.DictWithPWL(theLang, projectDict) + self.theDict = enchant.Dict(theLang) logger.debug("Enchant spell checking for language %s loaded" % theLang) except: logger.error("Failed to load enchant spell checking for language %s" % theLang) self.theDict = NWSpellEnchantDummy() + self._readProjectDictionary(projectDict) + for pWord in self.PROJW: + self.theDict.add_to_session(pWord) + return def checkWord(self, theWord): @@ -50,7 +51,8 @@ class NWSpellEnchant(NWSpellCheck): return self.theDict.suggest(theWord) def addWord(self, newWord): - self.theDict.add_to_pwl(newWord) + self.theDict.add_to_session(newWord) + NWSpellCheck.addWord(self, newWord) return def listDictionaries(self): @@ -58,10 +60,9 @@ class NWSpellEnchant(NWSpellCheck): for spTag, spProvider in enchant.list_dicts(): spList = [] if spTag[:2] in isoLanguage.ISO_639_1: - langName = isoLanguage.ISO_639_1[spTag[:2]] + spList.append(isoLanguage.ISO_639_1[spTag[:2]]) else: - langName = spTag[:2] - spList.append(langName) + spList.append(spTag[:2]) if len(spTag) > 3: spList.append("(%s)" % spTag[3:]) spList.append("[%s]" % spProvider.name) @@ -82,7 +83,7 @@ class NWSpellEnchantDummy: def suggest(self, theWord): return [] - def add_to_pwl(self, theWord): + def add_to_session(self, theWord): return # END Class NWSpellEnchantDummy diff --git a/nw/tools/spellsimple.py b/nw/tools/spellsimple.py index 2331f064..db7c38af 100644 --- a/nw/tools/spellsimple.py +++ b/nw/tools/spellsimple.py @@ -27,11 +27,12 @@ class NWSpellSimple(NWSpellCheck): def __init__(self): NWSpellCheck.__init__(self) - self.mainConf = nw.CONFIG logger.debug("Simple spell checking activated") return def setLanguage(self, theLang, projectDict=None): + + self.WORDS = [] dictFile = path.join(self.mainConf.dictPath,theLang+".dict") try: with open(dictFile,mode="r",encoding="utf-8") as wordsFile: @@ -44,16 +45,53 @@ class NWSpellSimple(NWSpellCheck): except Exception as e: logger.error("Failed to load spell check word list for language %s" % theLang) logger.error(str(e)) + + self._readProjectDictionary(projectDict) + for pWord in self.PROJW: + if pWord not in self.WORDS: + self.WORDS.append(pWord) + return def checkWord(self, theWord): - theWord = theWord.replace(self.mainConf.fmtSingleQuotes[1],"'").lower() + """Check if a word exists in the word list. Make sure to keep + this function as fast as possible as it is called for every + word by the syntax highlighter. + """ + theWord = theWord.replace(self.mainConf.fmtApostrophe,"'").lower() return theWord in self.WORDS def suggestWords(self, theWord): - return get_close_matches(theWord.lower(), self.WORDS, n=10, cutoff=0.75) + """Get suggestions for correct word from difflib, and make sure + the first character is upper case if that was also the case for + the word be3ing checked. Also make sure the apostrophe is + changed to the one in the dictionary, and then put back in the + results. + """ + theWord = theWord.strip() + if len(theWord) == 0: + return [] + + firstUp = theWord[0] == theWord[0].upper() + theWord = theWord.lower() + + theMatches = get_close_matches(theWord, self.WORDS, n=10, cutoff=0.75) + theOptions = [] + for aWord in theMatches: + if len(aWord) == 0: + continue + if firstUp: + aWord = aWord[0].upper() + aWord[1:] + aWord = aWord.replace("'",self.mainConf.fmtApostrophe) + theOptions.append(aWord) + + return theOptions def addWord(self, newWord): + newWord = newWord.strip().lower() + if newWord not in self.WORDS: + self.WORDS.append(newWord) + NWSpellCheck.addWord(self, newWord) return def listDictionaries(self):