diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py
index e4c95c6b..7681fe62 100644
--- a/nw/gui/elements/doceditor.py
+++ b/nw/gui/elements/doceditor.py
@@ -1007,7 +1007,7 @@ class GuiDocEditor(QTextEdit):
"""
if self.mainConf.spellTool == "enchant":
- from nw.tools.spellenchant import NWSpellEnchant
+ from nw.tools.spellcheck import NWSpellEnchant
self.theDict = NWSpellEnchant()
else:
self.theDict = NWSpellSimple()
diff --git a/nw/tools/__init__.py b/nw/tools/__init__.py
index d43736f9..14ddbc7c 100644
--- a/nw/tools/__init__.py
+++ b/nw/tools/__init__.py
@@ -4,8 +4,8 @@ from nw.tools.analyse import TextAnalysis
from nw.tools.legacy import projectMaintenance
from nw.tools.optionstate import OptionState
from nw.tools.spellcheck import NWSpellCheck
-from nw.tools.spellenchant import NWSpellEnchant
-from nw.tools.spellsimple import NWSpellSimple
+from nw.tools.spellcheck import NWSpellEnchant
+from nw.tools.spellcheck import NWSpellSimple
from nw.tools.translate import numberToWord
from nw.tools.wordcount import countWords
diff --git a/nw/tools/spellcheck.py b/nw/tools/spellcheck.py
index a5b534cd..f540fdc4 100644
--- a/nw/tools/spellcheck.py
+++ b/nw/tools/spellcheck.py
@@ -28,7 +28,8 @@
import logging
import nw
-from os import path
+from os import path, listdir
+from difflib import get_close_matches
from nw.constants import isoLanguage
@@ -108,3 +109,168 @@ class NWSpellCheck():
return
# END Class NWSpellCheck
+
+# ================================================================================================ #
+# Enchant Based SpellChecking
+# ================================================================================================ #
+
+class NWSpellEnchant(NWSpellCheck):
+
+ def __init__(self):
+ NWSpellCheck.__init__(self)
+ logger.debug("Enchant spell checking activated")
+ return
+
+ def setLanguage(self, theLang, projectDict=None):
+ """Load a dictionary for the language specified in the config.
+ If that fails, we load a dummy dictionary so that lookups don't
+ crash.
+ """
+ try:
+ import enchant
+ self.theDict = enchant.Dict(theLang)
+ self.spellLanguage = 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.spellLanguage = None
+
+ self._readProjectDictionary(projectDict)
+ for pWord in self.PROJW:
+ self.theDict.add_to_session(pWord)
+
+ return
+
+ def checkWord(self, theWord):
+ return self.theDict.check(theWord)
+
+ def suggestWords(self, theWord):
+ return self.theDict.suggest(theWord)
+
+ def addWord(self, newWord):
+ self.theDict.add_to_session(newWord)
+ NWSpellCheck.addWord(self, newWord)
+ return
+
+ def listDictionaries(self):
+ retList = []
+ for spTag, spProvider in enchant.list_dicts():
+ spName = "%s [%s]" % (self.expandLanguage(spTag), spProvider.name)
+ retList.append((spTag, spName))
+ return retList
+
+# END Class NWSpellEnchant
+
+class NWSpellEnchantDummy:
+
+ def __init__(self):
+ return
+
+ def check(self, theWord):
+ return True
+
+ def suggest(self, theWord):
+ return []
+
+ def add_to_session(self, theWord):
+ return
+
+# END Class NWSpellEnchantDummy
+
+# ================================================================================================ #
+# Fallback SpellChecking Using difflib
+# ================================================================================================ #
+
+class NWSpellSimple(NWSpellCheck):
+
+ WORDS = []
+
+ def __init__(self):
+ NWSpellCheck.__init__(self)
+ 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:
+ for theLine in wordsFile:
+ if len(theLine) == 0 or theLine.startswith("#"):
+ continue
+ self.WORDS.append(theLine.strip().lower())
+ logger.debug("Spell check word list for language %s loaded" % theLang)
+ logger.debug("Word list contains %d words" % len(self.WORDS))
+ self.spellLanguage = theLang
+ except Exception as e:
+ logger.error("Failed to load spell check word list for language %s" % theLang)
+ logger.error(str(e))
+ self.spellLanguage = None
+
+ self._readProjectDictionary(projectDict)
+ for pWord in self.PROJW:
+ if pWord not in self.WORDS:
+ self.WORDS.append(pWord)
+
+ return
+
+ def checkWord(self, theWord):
+ """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):
+ """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):
+
+ retList = []
+ for dictFile in listdir(self.mainConf.dictPath):
+
+ theBits = path.splitext(dictFile)
+ if len(theBits) != 2:
+ continue
+ if theBits[1] != ".dict":
+ continue
+
+ spName = "%s [Internal]" % self.expandLanguage(theBits[0])
+ retList.append((theBits[0], spName))
+
+ return retList
+
+# END Class NWSpellSimple
diff --git a/nw/tools/spellenchant.py b/nw/tools/spellenchant.py
deleted file mode 100644
index 4e7400a0..00000000
--- a/nw/tools/spellenchant.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# -*- coding: utf-8 -*-
-"""novelWriter Spell Check Wrapper : pyEnchant
-
- novelWriter – Spell Check Wrapper : pyEnchant
-===============================================
- Wrapper class for spell checking with pyEnchant
-
- File History:
- Created: 2019-06-11 [0.1.5]
-
- This file is a part of novelWriter
- Copyright 2020, Veronica Berglyd Olsen
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-"""
-
-import logging
-import nw
-try:
- import enchant
-except:
- # No need to do anything
- # setLanguage will fall back to dummy dictionary
- pass
-
-from nw.tools.spellcheck import NWSpellCheck
-
-logger = logging.getLogger(__name__)
-
-class NWSpellEnchant(NWSpellCheck):
-
- def __init__(self):
- NWSpellCheck.__init__(self)
- logger.debug("Enchant spell checking activated")
- return
-
- def setLanguage(self, theLang, projectDict=None):
- """Load a dictionary for the language specified in the config.
- If that fails, we load a dummy dictionary so that lookups don't
- crash.
- """
- try:
- self.theDict = enchant.Dict(theLang)
- self.spellLanguage = 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.spellLanguage = None
-
- self._readProjectDictionary(projectDict)
- for pWord in self.PROJW:
- self.theDict.add_to_session(pWord)
-
- return
-
- def checkWord(self, theWord):
- return self.theDict.check(theWord)
-
- def suggestWords(self, theWord):
- return self.theDict.suggest(theWord)
-
- def addWord(self, newWord):
- self.theDict.add_to_session(newWord)
- NWSpellCheck.addWord(self, newWord)
- return
-
- def listDictionaries(self):
- retList = []
- for spTag, spProvider in enchant.list_dicts():
- spName = "%s [%s]" % (self.expandLanguage(spTag), spProvider.name)
- retList.append((spTag, spName))
- return retList
-
-# END Class NWSpellEnchant
-
-class NWSpellEnchantDummy:
-
- def __init__(self):
- return
-
- def check(self, theWord):
- return True
-
- def suggest(self, theWord):
- return []
-
- def add_to_session(self, theWord):
- return
-
-# END Class NWSpellEnchantDummy
diff --git a/nw/tools/spellsimple.py b/nw/tools/spellsimple.py
deleted file mode 100644
index 63a8847b..00000000
--- a/nw/tools/spellsimple.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# -*- coding: utf-8 -*-
-"""novelWriter Spell Check Simple
-
- novelWriter – Spell Check Simple
-==================================
- Simple spell checker based on difflib
-
- File History:
- Created: 2019-06-11 [0.1.5]
-
- This file is a part of novelWriter
- Copyright 2020, Veronica Berglyd Olsen
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-"""
-
-import logging
-import nw
-
-from os import path, listdir
-from difflib import get_close_matches
-
-logger = logging.getLogger(__name__)
-
-from nw.tools.spellcheck import NWSpellCheck
-
-class NWSpellSimple(NWSpellCheck):
-
- WORDS = []
-
- def __init__(self):
- NWSpellCheck.__init__(self)
- 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:
- for theLine in wordsFile:
- if len(theLine) == 0 or theLine.startswith("#"):
- continue
- self.WORDS.append(theLine.strip().lower())
- logger.debug("Spell check word list for language %s loaded" % theLang)
- logger.debug("Word list contains %d words" % len(self.WORDS))
- self.spellLanguage = theLang
- except Exception as e:
- logger.error("Failed to load spell check word list for language %s" % theLang)
- logger.error(str(e))
- self.spellLanguage = None
-
- self._readProjectDictionary(projectDict)
- for pWord in self.PROJW:
- if pWord not in self.WORDS:
- self.WORDS.append(pWord)
-
- return
-
- def checkWord(self, theWord):
- """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):
- """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):
-
- retList = []
- for dictFile in listdir(self.mainConf.dictPath):
-
- theBits = path.splitext(dictFile)
- if len(theBits) != 2:
- continue
- if theBits[1] != ".dict":
- continue
-
- spName = "%s [Internal]" % self.expandLanguage(theBits[0])
- retList.append((theBits[0], spName))
-
- return retList
-
-# END Class NWSpellSimple