From 9204003f57d8e1227b5c1aeb6d33163e208424ad Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 20:09:51 +0200 Subject: [PATCH 1/9] Add some pyqtSlot decorators as they apparently improve perforamce a tiny bit --- nw/gui/elements/doceditor.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 5ed52888..e4c95c6b 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -30,7 +30,7 @@ import nw from time import time -from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtCore import Qt, QTimer, pyqtSlot from PyQt5.QtWidgets import ( qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox, QLabel ) @@ -589,6 +589,7 @@ class GuiDocEditor(QTextEdit): # Signals and Slots ## + @pyqtSlot(int, int, int) def _docChange(self, thePos, charsRemoved, charsAdded): """Triggered by QTextDocument->contentsChanged. This also triggers the syntax highlighter. @@ -602,6 +603,7 @@ class GuiDocEditor(QTextEdit): self._docAutoReplace(self.qDocument.findBlock(thePos)) return + @pyqtSlot("QPoint") def _openContextMenu(self, thePos): """Triggered by right click to open the context menu. Also triggered by the Ctrl+. shortcut. @@ -663,6 +665,7 @@ class GuiDocEditor(QTextEdit): self.hLight.rehighlightBlock(theCursor.block()) return + @pyqtSlot() def _runCounter(self): """Decide whether to run the word counter, or stop the timer due to inactivity. @@ -678,6 +681,7 @@ class GuiDocEditor(QTextEdit): self.wCounter.start() return + @pyqtSlot() def _updateCounts(self): """Slot for the word counter's finished signal """ @@ -730,6 +734,8 @@ class GuiDocEditor(QTextEdit): return True def _insertHardBreak(self): + """Inserts a hard line break at the cursor position. + """ theCursor = self.textCursor() theCursor.beginEditBlock() theCursor.insertText(" \n") @@ -737,6 +743,8 @@ class GuiDocEditor(QTextEdit): return def _insertNonBreakingSpace(self): + """Inserts a non-breaking space at the cursor position. + """ theCursor = self.textCursor() theCursor.beginEditBlock() theCursor.insertText(nwUnicode.U_NBSP) From 704d9a11e473890037017327c431adc7da503721 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 20:41:39 +0200 Subject: [PATCH 2/9] Merged the spell checking classes into one file --- nw/gui/elements/doceditor.py | 2 +- nw/tools/__init__.py | 4 +- nw/tools/spellcheck.py | 168 ++++++++++++++++++++++++++++++++++- nw/tools/spellenchant.py | 102 --------------------- nw/tools/spellsimple.py | 129 --------------------------- 5 files changed, 170 insertions(+), 235 deletions(-) delete mode 100644 nw/tools/spellenchant.py delete mode 100644 nw/tools/spellsimple.py 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 From 5cc036e125497d8cb0c25731c57ad3f7fa8e2e18 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 20:57:03 +0200 Subject: [PATCH 3/9] Fixed a bug in language lookup for enchant spelling --- nw/tools/spellcheck.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/nw/tools/spellcheck.py b/nw/tools/spellcheck.py index f540fdc4..fda4022d 100644 --- a/nw/tools/spellcheck.py +++ b/nw/tools/spellcheck.py @@ -35,6 +35,10 @@ from nw.constants import isoLanguage logger = logging.getLogger(__name__) +# ================================================================================================ # +# SpellChecking SuperClass +# ================================================================================================ # + class NWSpellCheck(): SP_INTERNAL = "internal" @@ -155,9 +159,13 @@ class NWSpellEnchant(NWSpellCheck): def listDictionaries(self): retList = [] - for spTag, spProvider in enchant.list_dicts(): - spName = "%s [%s]" % (self.expandLanguage(spTag), spProvider.name) - retList.append((spTag, spName)) + try: + import enchant + for spTag, spProvider in enchant.list_dicts(): + spName = "%s [%s]" % (self.expandLanguage(spTag), spProvider.name) + retList.append((spTag, spName)) + except: + logger.error("Failed to list languages for enchant spell checking") return retList # END Class NWSpellEnchant From 386020bcf816610ddb4e2fc3b7c6b56b433a19bb Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 20:58:34 +0200 Subject: [PATCH 4/9] Renamed 'project' folder to 'core' --- nw/convert/tokenizer.py | 2 +- nw/core/__init__.py | 11 +++++++++++ nw/{project => core}/document.py | 0 nw/{project => core}/index.py | 0 nw/{project => core}/project.py | 0 nw/gui/dialogs/docmerge.py | 2 +- nw/gui/dialogs/docsplit.py | 2 +- nw/gui/elements/doceditor.py | 2 +- nw/gui/elements/doctree.py | 2 +- nw/guimain.py | 2 +- nw/project/__init__.py | 11 ----------- tests/test_item.py | 2 +- tests/test_project.py | 4 ++-- 13 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 nw/core/__init__.py rename nw/{project => core}/document.py (100%) rename nw/{project => core}/index.py (100%) rename nw/{project => core}/project.py (100%) delete mode 100644 nw/project/__init__.py diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index f891a9f7..59508d4c 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -32,7 +32,7 @@ import nw from operator import itemgetter from PyQt5.QtCore import QRegularExpression -from nw.project.document import NWDoc +from nw.core.document import NWDoc from nw.tools.translate import numberToWord from nw.constants import nwItemLayout diff --git a/nw/core/__init__.py b/nw/core/__init__.py new file mode 100644 index 00000000..8bc04dcd --- /dev/null +++ b/nw/core/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- + +from nw.core.document import NWDoc +from nw.core.index import NWIndex +from nw.core.project import NWProject + +__all__ = [ + "NWDoc", + "NWIndex", + "NWProject", +] diff --git a/nw/project/document.py b/nw/core/document.py similarity index 100% rename from nw/project/document.py rename to nw/core/document.py diff --git a/nw/project/index.py b/nw/core/index.py similarity index 100% rename from nw/project/index.py rename to nw/core/index.py diff --git a/nw/project/project.py b/nw/core/project.py similarity index 100% rename from nw/project/project.py rename to nw/core/project.py diff --git a/nw/gui/dialogs/docmerge.py b/nw/gui/dialogs/docmerge.py index 887e8b72..097f4217 100644 --- a/nw/gui/dialogs/docmerge.py +++ b/nw/gui/dialogs/docmerge.py @@ -34,7 +34,7 @@ from PyQt5.QtWidgets import ( QListWidget, QAbstractItemView, QListWidgetItem ) from nw.constants import nwAlert, nwItemType -from nw.project import NWDoc +from nw.core import NWDoc logger = logging.getLogger(__name__) diff --git a/nw/gui/dialogs/docsplit.py b/nw/gui/dialogs/docsplit.py index 55be4ee4..bfb4e8ee 100644 --- a/nw/gui/dialogs/docsplit.py +++ b/nw/gui/dialogs/docsplit.py @@ -34,7 +34,7 @@ from PyQt5.QtWidgets import ( QListWidget, QAbstractItemView, QListWidgetItem ) from nw.constants import nwAlert, nwItemType, nwItemClass, nwItemLayout -from nw.project import NWDoc +from nw.core import NWDoc logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 7681fe62..f7d494e1 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -39,7 +39,7 @@ from PyQt5.QtGui import ( QTextDocument, QCursor ) -from nw.project import NWDoc +from nw.core import NWDoc from nw.gui.tools import GuiDocHighlighter, WordCounter from nw.gui.elements.doctitlebar import GuiDocTitleBar from nw.tools import NWSpellSimple diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index 09330346..92a006de 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -34,7 +34,7 @@ from PyQt5.QtWidgets import ( QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication, QMessageBox ) -from nw.project import NWDoc +from nw.core import NWDoc from nw.constants import ( nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert ) diff --git a/nw/guimain.py b/nw/guimain.py index 935c1fb2..4241c043 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -45,7 +45,7 @@ from nw.gui import ( GuiConfigEditor, GuiProjectEditor, GuiItemEditor, GuiProjectOutline, GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad ) -from nw.project import NWProject, NWDoc, NWIndex +from nw.core import NWProject, NWDoc, NWIndex from nw.tools import countWords from nw.constants import nwFiles, nwItemType, nwAlert diff --git a/nw/project/__init__.py b/nw/project/__init__.py deleted file mode 100644 index f2a0fe0c..00000000 --- a/nw/project/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- - -from nw.project.document import NWDoc -from nw.project.index import NWIndex -from nw.project.project import NWProject - -__all__ = [ - "NWDoc", - "NWIndex", - "NWProject", -] diff --git a/tests/test_item.py b/tests/test_item.py index b58f1b7e..64268e62 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -9,7 +9,7 @@ from lxml import etree from nwdummy import DummyMain from nw.config import Config -from nw.project.project import NWProject, NWItem +from nw.core.project import NWProject, NWItem from nw.constants import nwItemClass, nwItemType, nwItemLayout theConf = Config() diff --git a/tests/test_project.py b/tests/test_project.py index c029fbba..7d920a37 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -10,8 +10,8 @@ from nwtools import * from nwdummy import DummyMain from nw.config import Config -from nw.project.project import NWProject -from nw.project.index import NWIndex +from nw.core.project import NWProject +from nw.core.index import NWIndex from nw.constants import nwItemClass theConf = Config() From 9b049b6469fd7eab16896cc9a2707323b6129315 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 21:02:30 +0200 Subject: [PATCH 5/9] Moved spell checker classes to core folder --- nw/core/__init__.py | 6 ++++++ nw/{tools => core}/spellcheck.py | 0 nw/gui/dialogs/configeditor.py | 2 +- nw/gui/elements/doceditor.py | 4 ++-- nw/gui/statusbar.py | 2 +- nw/tools/__init__.py | 6 ------ 6 files changed, 10 insertions(+), 10 deletions(-) rename nw/{tools => core}/spellcheck.py (100%) diff --git a/nw/core/__init__.py b/nw/core/__init__.py index 8bc04dcd..29ba7051 100644 --- a/nw/core/__init__.py +++ b/nw/core/__init__.py @@ -3,9 +3,15 @@ from nw.core.document import NWDoc from nw.core.index import NWIndex from nw.core.project import NWProject +from nw.core.spellcheck import NWSpellCheck +from nw.core.spellcheck import NWSpellEnchant +from nw.core.spellcheck import NWSpellSimple __all__ = [ "NWDoc", "NWIndex", "NWProject", + "NWSpellCheck", + "NWSpellEnchant", + "NWSpellSimple", ] diff --git a/nw/tools/spellcheck.py b/nw/core/spellcheck.py similarity index 100% rename from nw/tools/spellcheck.py rename to nw/core/spellcheck.py diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index ac0ed592..7a6f167b 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -39,7 +39,7 @@ from PyQt5.QtWidgets import ( ) from nw.additions import QSwitch, QConfigLayout -from nw.tools import NWSpellCheck, NWSpellSimple, NWSpellEnchant +from nw.core import NWSpellCheck, NWSpellSimple, NWSpellEnchant from nw.constants import nwAlert, nwQuotes logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index f7d494e1..a6d76958 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -42,7 +42,7 @@ from PyQt5.QtGui import ( from nw.core import NWDoc from nw.gui.tools import GuiDocHighlighter, WordCounter from nw.gui.elements.doctitlebar import GuiDocTitleBar -from nw.tools import NWSpellSimple +from nw.core import NWSpellSimple from nw.constants import nwUnicode, nwDocAction logger = logging.getLogger(__name__) @@ -1007,7 +1007,7 @@ class GuiDocEditor(QTextEdit): """ if self.mainConf.spellTool == "enchant": - from nw.tools.spellcheck import NWSpellEnchant + from nw.core.spellcheck import NWSpellEnchant self.theDict = NWSpellEnchant() else: self.theDict = NWSpellSimple() diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py index f2492910..d815dd54 100644 --- a/nw/gui/statusbar.py +++ b/nw/gui/statusbar.py @@ -34,7 +34,7 @@ from PyQt5.QtCore import Qt, QTimer from PyQt5.QtGui import QColor, QPixmap, QFont from PyQt5.QtWidgets import QStatusBar, QLabel -from nw.tools import NWSpellCheck +from nw.core import NWSpellCheck logger = logging.getLogger(__name__) diff --git a/nw/tools/__init__.py b/nw/tools/__init__.py index 14ddbc7c..271db24c 100644 --- a/nw/tools/__init__.py +++ b/nw/tools/__init__.py @@ -3,9 +3,6 @@ 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.spellcheck import NWSpellEnchant -from nw.tools.spellcheck import NWSpellSimple from nw.tools.translate import numberToWord from nw.tools.wordcount import countWords @@ -13,9 +10,6 @@ __all__ = [ "TextAnalysis", "projectMaintenance", "OptionState", - "NWSpellCheck", - "NWSpellEnchant", - "NWSpellSimple", "numberToWord", "countWords", ] From b0c71fb47da7f0d02ebc8d79f6d06e9ffd868b57 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 21:28:05 +0200 Subject: [PATCH 6/9] Removed the nw/tools folder and moved or merged the code in elsewhere --- {nw/tools => lib/text}/analyse.py | 0 nw/convert/tokenizer.py | 2 +- nw/core/__init__.py | 6 + nw/core/index.py | 2 +- nw/core/project.py | 3 +- nw/core/tools.py | 206 ++++++++++++++++++++++++++++++ nw/gui/__init__.py | 2 + nw/gui/tools/__init__.py | 2 + nw/{ => gui}/tools/optionstate.py | 0 nw/gui/tools/wordcounter.py | 2 +- nw/guimain.py | 3 +- nw/tools/__init__.py | 15 --- nw/tools/legacy.py | 78 ----------- nw/tools/translate.py | 106 --------------- nw/tools/wordcount.py | 76 ----------- 15 files changed, 222 insertions(+), 281 deletions(-) rename {nw/tools => lib/text}/analyse.py (100%) create mode 100644 nw/core/tools.py rename nw/{ => gui}/tools/optionstate.py (100%) delete mode 100644 nw/tools/__init__.py delete mode 100644 nw/tools/legacy.py delete mode 100644 nw/tools/translate.py delete mode 100644 nw/tools/wordcount.py diff --git a/nw/tools/analyse.py b/lib/text/analyse.py similarity index 100% rename from nw/tools/analyse.py rename to lib/text/analyse.py diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index 59508d4c..4ac99377 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -33,7 +33,7 @@ from operator import itemgetter from PyQt5.QtCore import QRegularExpression from nw.core.document import NWDoc -from nw.tools.translate import numberToWord +from nw.core.tools import numberToWord from nw.constants import nwItemLayout logger = logging.getLogger(__name__) diff --git a/nw/core/__init__.py b/nw/core/__init__.py index 29ba7051..a608acd7 100644 --- a/nw/core/__init__.py +++ b/nw/core/__init__.py @@ -6,6 +6,9 @@ from nw.core.project import NWProject from nw.core.spellcheck import NWSpellCheck from nw.core.spellcheck import NWSpellEnchant from nw.core.spellcheck import NWSpellSimple +from nw.core.tools import countWords +from nw.core.tools import projectMaintenance +from nw.core.tools import numberToWord __all__ = [ "NWDoc", @@ -14,4 +17,7 @@ __all__ = [ "NWSpellCheck", "NWSpellEnchant", "NWSpellSimple", + "countWords", + "projectMaintenance", + "numberToWord", ] diff --git a/nw/core/index.py b/nw/core/index.py index 9cc1098b..617ddb65 100644 --- a/nw/core/index.py +++ b/nw/core/index.py @@ -35,7 +35,7 @@ from time import time from nw.constants import ( nwFiles, nwKeyWords, nwItemType, nwItemClass, nwItemLayout, nwAlert ) -from nw.tools import countWords +from nw.core.tools import countWords logger = logging.getLogger(__name__) diff --git a/nw/core/project.py b/nw/core/project.py index fb4f340a..ef6558cf 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -40,7 +40,8 @@ from datetime import datetime from time import time from shutil import make_archive -from nw.tools import projectMaintenance, OptionState +from nw.gui.tools import OptionState +from nw.core.tools import projectMaintenance from nw.common import checkString, checkBool, checkInt from nw.constants import ( nwFiles, nwConst, nwItemType, nwItemClass, nwItemLayout, nwAlert diff --git a/nw/core/tools.py b/nw/core/tools.py new file mode 100644 index 00000000..f90ae584 --- /dev/null +++ b/nw/core/tools.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +"""novelWriter Word Counter + + novelWriter – Word Counter +============================ + Simple word counter + + File History: + Created: 2019-04-22 [0.0.1] countWords + Moved: 2019-05-30 [0.1.4] countWords + Created: 2020-02-13 [0.4.3] projectMaintenance + + 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, unlink, rmdir + +logger = logging.getLogger(__name__) + +def countWords(theText): + """Count words in a piece of text, skipping special syntax and + comments. + """ + + charCount = 0 + wordCount = 0 + paraCount = 0 + prevEmpty = True + + for aLine in theText.splitlines(): + + countPara = True + theLen = len(aLine) + + if theLen == 0: + prevEmpty = True + continue + if aLine[0] == "@" or aLine[0] == "%": + continue + + if aLine[0:5] == "#### ": + wordCount -= 1 + charCount -= 5 + countPara = False + elif aLine[0:4] == "### ": + wordCount -= 1 + charCount -= 4 + countPara = False + elif aLine[0:3] == "## ": + wordCount -= 1 + charCount -= 3 + countPara = False + elif aLine[0:2] == "# ": + wordCount -= 1 + charCount -= 2 + countPara = False + + theBuff = aLine.replace("–"," ").replace("—"," ") + wordCount += len(theBuff.split()) + charCount += theLen + if countPara and prevEmpty: + paraCount += 1 + prevEmpty = countPara == False + + return charCount, wordCount, paraCount + +def projectMaintenance(theProject): + """Wrapper class for handling various tasks related to managing old + projects with content from older versions of novelWriter. + """ + + # Remove no longer used project cache folder + if path.isdir(theProject.projPath): + cacheDir = path.join(theProject.projPath, "cache") + if path.isdir(cacheDir): + logger.info("Deprecated cache folder found") + rmList = [] + for i in range(10): + rmList.append(path.join(cacheDir, "nwProject.nwx.%d" % i)) + rmList.append(path.join(cacheDir, "projCount.txt")) + for rmFile in rmList: + if path.isfile(rmFile): + logger.info("Deleting: %s" % rmFile) + try: + unlink(rmFile) + except Exception as e: + logger.error(str(e)) + logger.info("Deleting: %s" % cacheDir) + try: + rmdir(cacheDir) + except Exception as e: + logger.error(str(e)) + + # Remove no longer used meta files + rmList = [] + rmList.append(path.join(theProject.projMeta, "mainOptions.json")) + rmList.append(path.join(theProject.projMeta, "exportOptions.json")) + rmList.append(path.join(theProject.projMeta, "outlineOptions.json")) + rmList.append(path.join(theProject.projMeta, "timelineOptions.json")) + rmList.append(path.join(theProject.projMeta, "docMergeOptions.json")) + rmList.append(path.join(theProject.projMeta, "sessionLogOptions.json")) + for rmFile in rmList: + if path.isfile(rmFile): + logger.info("Deleting: %s" % rmFile) + try: + unlink(rmFile) + except Exception as e: + logger.error(str(e)) + + return + +def numberToWord(numVal, theLanguage): + """Wrapper for converting numbers to words for chapter headings. + """ + numWord = "" + if theLanguage == "en": + numWord = _numberToWordEN(numVal) + else: + numWord = _numberToWordEN(numVal) + # print("%4d : %s" % (numVal, numWord)) + return numWord + +def _numberToWordEN(numVal): + """Convert numbers to English words. + """ + + numWord = "" + oneWord = "" + tenWord = "" + hunWord = "" + + if numVal == 0: + return "Zero" + + oneVal = numVal % 10 + tenVal = (numVal-oneVal) % 100 + hunVal = (numVal-tenVal-oneVal) % 1000 + + if hunVal == 100: hunWord = "One Hundred" + if hunVal == 200: hunWord = "Two Hundred" + if hunVal == 300: hunWord = "Three Hundred" + if hunVal == 400: hunWord = "Four Hundred" + if hunVal == 500: hunWord = "Five Hundred" + if hunVal == 600: hunWord = "Six Hundred" + if hunVal == 700: hunWord = "Seven Hundred" + if hunVal == 800: hunWord = "Eight Hundred" + if hunVal == 900: hunWord = "Nine Hundred" + + if tenVal == 20: tenWord = "Twenty" + if tenVal == 30: tenWord = "Thirty" + if tenVal == 40: tenWord = "Forty" + if tenVal == 50: tenWord = "Fifty" + if tenVal == 60: tenWord = "Sixty" + if tenVal == 70: tenWord = "Seventy" + if tenVal == 80: tenWord = "Eighty" + if tenVal == 90: tenWord = "Ninety" + + if tenVal == 10: + if oneVal == 0: oneWord = "Ten" + if oneVal == 1: oneWord = "Eleven" + if oneVal == 2: oneWord = "Twelve" + if oneVal == 3: oneWord = "Thirteen" + if oneVal == 4: oneWord = "Fourteen" + if oneVal == 5: oneWord = "Fifteen" + if oneVal == 6: oneWord = "Sixteen" + if oneVal == 7: oneWord = "Seventeen" + if oneVal == 8: oneWord = "Eighteen" + if oneVal == 9: oneWord = "Nineteen" + numWord = ("%s %s" % (hunWord, oneWord)).strip() + else: + if oneVal == 0: oneWord = "" + if oneVal == 1: oneWord = "One" + if oneVal == 2: oneWord = "Two" + if oneVal == 3: oneWord = "Three" + if oneVal == 4: oneWord = "Four" + if oneVal == 5: oneWord = "Five" + if oneVal == 6: oneWord = "Six" + if oneVal == 7: oneWord = "Seven" + if oneVal == 8: oneWord = "Eight" + if oneVal == 9: oneWord = "Nine" + if tenVal == 0: + numWord = ("%s %s" % (hunWord, oneWord)).strip() + else: + if oneVal == 0: + numWord = ("%s %s" % (hunWord, tenWord)).strip() + else: + numWord = ("%s %s-%s" % (hunWord, tenWord, oneWord)).strip() + + return numWord diff --git a/nw/gui/__init__.py b/nw/gui/__init__.py index d5f7e67b..a39d93ad 100644 --- a/nw/gui/__init__.py +++ b/nw/gui/__init__.py @@ -29,6 +29,7 @@ from nw.gui.elements.viewdetails import GuiDocViewDetails # Tools from nw.gui.tools.dochighlight import GuiDocHighlighter +from nw.gui.tools.optionstate import OptionState from nw.gui.tools.wordcounter import WordCounter __all__ = [ @@ -54,5 +55,6 @@ __all__ = [ "GuiSearchBar", "GuiDocViewDetails", "GuiDocHighlighter", + "OptionState", "WordCounter", ] diff --git a/nw/gui/tools/__init__.py b/nw/gui/tools/__init__.py index 4899f398..cc6cfdfa 100644 --- a/nw/gui/tools/__init__.py +++ b/nw/gui/tools/__init__.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- from nw.gui.tools.dochighlight import GuiDocHighlighter +from nw.gui.tools.optionstate import OptionState from nw.gui.tools.wordcounter import WordCounter __all__ = [ "GuiDocHighlighter", + "OptionState", "WordCounter", ] diff --git a/nw/tools/optionstate.py b/nw/gui/tools/optionstate.py similarity index 100% rename from nw/tools/optionstate.py rename to nw/gui/tools/optionstate.py diff --git a/nw/gui/tools/wordcounter.py b/nw/gui/tools/wordcounter.py index b7cb2045..24a0b9ca 100644 --- a/nw/gui/tools/wordcounter.py +++ b/nw/gui/tools/wordcounter.py @@ -30,7 +30,7 @@ import nw from PyQt5.QtCore import QThread -from nw.tools.wordcount import countWords +from nw.core.tools import countWords logger = logging.getLogger(__name__) diff --git a/nw/guimain.py b/nw/guimain.py index 4241c043..b3356301 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -45,8 +45,7 @@ from nw.gui import ( GuiConfigEditor, GuiProjectEditor, GuiItemEditor, GuiProjectOutline, GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad ) -from nw.core import NWProject, NWDoc, NWIndex -from nw.tools import countWords +from nw.core import NWProject, NWDoc, NWIndex, countWords from nw.constants import nwFiles, nwItemType, nwAlert logger = logging.getLogger(__name__) diff --git a/nw/tools/__init__.py b/nw/tools/__init__.py deleted file mode 100644 index 271db24c..00000000 --- a/nw/tools/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -from nw.tools.analyse import TextAnalysis -from nw.tools.legacy import projectMaintenance -from nw.tools.optionstate import OptionState -from nw.tools.translate import numberToWord -from nw.tools.wordcount import countWords - -__all__ = [ - "TextAnalysis", - "projectMaintenance", - "OptionState", - "numberToWord", - "countWords", -] diff --git a/nw/tools/legacy.py b/nw/tools/legacy.py deleted file mode 100644 index b676caf7..00000000 --- a/nw/tools/legacy.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- -"""novelWriter Legacy Tools - - novelWriter – Legacy Tools -============================ - Various functions to handle old projects - - File History: - Created: 2020-02-13 [0.4.3] - - 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, unlink, rmdir - -logger = logging.getLogger(__name__) - -def projectMaintenance(theProject): - """Wrapper class for handling various tasks related to managing old - projects with content from older versions of novelWriter. - """ - - # Remove no longer used project cache folder - if path.isdir(theProject.projPath): - cacheDir = path.join(theProject.projPath, "cache") - if path.isdir(cacheDir): - logger.info("Deprecated cache folder found") - rmList = [] - for i in range(10): - rmList.append(path.join(cacheDir, "nwProject.nwx.%d" % i)) - rmList.append(path.join(cacheDir, "projCount.txt")) - for rmFile in rmList: - if path.isfile(rmFile): - logger.info("Deleting: %s" % rmFile) - try: - unlink(rmFile) - except Exception as e: - logger.error(str(e)) - logger.info("Deleting: %s" % cacheDir) - try: - rmdir(cacheDir) - except Exception as e: - logger.error(str(e)) - - # Remove no longer used meta files - rmList = [] - rmList.append(path.join(theProject.projMeta, "mainOptions.json")) - rmList.append(path.join(theProject.projMeta, "exportOptions.json")) - rmList.append(path.join(theProject.projMeta, "outlineOptions.json")) - rmList.append(path.join(theProject.projMeta, "timelineOptions.json")) - rmList.append(path.join(theProject.projMeta, "docMergeOptions.json")) - rmList.append(path.join(theProject.projMeta, "sessionLogOptions.json")) - for rmFile in rmList: - if path.isfile(rmFile): - logger.info("Deleting: %s" % rmFile) - try: - unlink(rmFile) - except Exception as e: - logger.error(str(e)) - - return diff --git a/nw/tools/translate.py b/nw/tools/translate.py deleted file mode 100644 index dd1f72f3..00000000 --- a/nw/tools/translate.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- -"""novelWriter Translate Tools - - novelWriter – Translate Tools -=============================== - Various translate tools - - File History: - Created: 2019-10-13 [0.2.3] - - 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 - -logger = logging.getLogger(__name__) - -def numberToWord(numVal, theLanguage): - numWord = "" - if theLanguage == "en": - numWord = _numberToWordEN(numVal) - else: - numWord = _numberToWordEN(numVal) - # print("%4d : %s" % (numVal, numWord)) - return numWord - -def _numberToWordEN(numVal): - - numWord = "" - oneWord = "" - tenWord = "" - hunWord = "" - - if numVal == 0: - return "Zero" - - oneVal = numVal % 10 - tenVal = (numVal-oneVal) % 100 - hunVal = (numVal-tenVal-oneVal) % 1000 - - if hunVal == 100: hunWord = "One Hundred" - if hunVal == 200: hunWord = "Two Hundred" - if hunVal == 300: hunWord = "Three Hundred" - if hunVal == 400: hunWord = "Four Hundred" - if hunVal == 500: hunWord = "Five Hundred" - if hunVal == 600: hunWord = "Six Hundred" - if hunVal == 700: hunWord = "Seven Hundred" - if hunVal == 800: hunWord = "Eight Hundred" - if hunVal == 900: hunWord = "Nine Hundred" - - if tenVal == 20: tenWord = "Twenty" - if tenVal == 30: tenWord = "Thirty" - if tenVal == 40: tenWord = "Forty" - if tenVal == 50: tenWord = "Fifty" - if tenVal == 60: tenWord = "Sixty" - if tenVal == 70: tenWord = "Seventy" - if tenVal == 80: tenWord = "Eighty" - if tenVal == 90: tenWord = "Ninety" - - if tenVal == 10: - if oneVal == 0: oneWord = "Ten" - if oneVal == 1: oneWord = "Eleven" - if oneVal == 2: oneWord = "Twelve" - if oneVal == 3: oneWord = "Thirteen" - if oneVal == 4: oneWord = "Fourteen" - if oneVal == 5: oneWord = "Fifteen" - if oneVal == 6: oneWord = "Sixteen" - if oneVal == 7: oneWord = "Seventeen" - if oneVal == 8: oneWord = "Eighteen" - if oneVal == 9: oneWord = "Nineteen" - numWord = ("%s %s" % (hunWord, oneWord)).strip() - else: - if oneVal == 0: oneWord = "" - if oneVal == 1: oneWord = "One" - if oneVal == 2: oneWord = "Two" - if oneVal == 3: oneWord = "Three" - if oneVal == 4: oneWord = "Four" - if oneVal == 5: oneWord = "Five" - if oneVal == 6: oneWord = "Six" - if oneVal == 7: oneWord = "Seven" - if oneVal == 8: oneWord = "Eight" - if oneVal == 9: oneWord = "Nine" - if tenVal == 0: - numWord = ("%s %s" % (hunWord, oneWord)).strip() - else: - if oneVal == 0: - numWord = ("%s %s" % (hunWord, tenWord)).strip() - else: - numWord = ("%s %s-%s" % (hunWord, tenWord, oneWord)).strip() - - return numWord diff --git a/nw/tools/wordcount.py b/nw/tools/wordcount.py deleted file mode 100644 index 72043158..00000000 --- a/nw/tools/wordcount.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -"""novelWriter Word Counter - - novelWriter – Word Counter -============================ - Simple word counter - - File History: - Created: 2019-04-22 [0.0.1] - Moved: 2019-05-30 [0.1.4] - - 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 - -logger = logging.getLogger(__name__) - -def countWords(theText): - - charCount = 0 - wordCount = 0 - paraCount = 0 - prevEmpty = True - - for aLine in theText.splitlines(): - - countPara = True - theLen = len(aLine) - - if theLen == 0: - prevEmpty = True - continue - if aLine[0] == "@" or aLine[0] == "%": - continue - - if aLine[0:5] == "#### ": - wordCount -= 1 - charCount -= 5 - countPara = False - elif aLine[0:4] == "### ": - wordCount -= 1 - charCount -= 4 - countPara = False - elif aLine[0:3] == "## ": - wordCount -= 1 - charCount -= 3 - countPara = False - elif aLine[0:2] == "# ": - wordCount -= 1 - charCount -= 2 - countPara = False - - theBuff = aLine.replace("–"," ").replace("—"," ") - wordCount += len(theBuff.split()) - charCount += theLen - if countPara and prevEmpty: - paraCount += 1 - prevEmpty = countPara == False - - return charCount, wordCount, paraCount From 894bc41f510249c6f94b57d247a31878f81cc143 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 21:32:38 +0200 Subject: [PATCH 7/9] Moved the additions folder into the gui folder as it only contains gui elements --- nw/additions/__init__.py | 8 -------- nw/gui/__init__.py | 6 ++++++ nw/gui/additions/__init__.py | 8 ++++++++ nw/{ => gui}/additions/qconfiglayout.py | 0 nw/{ => gui}/additions/qswitch.py | 0 nw/gui/dialogs/configeditor.py | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) delete mode 100644 nw/additions/__init__.py create mode 100644 nw/gui/additions/__init__.py rename nw/{ => gui}/additions/qconfiglayout.py (100%) rename nw/{ => gui}/additions/qswitch.py (100%) diff --git a/nw/additions/__init__.py b/nw/additions/__init__.py deleted file mode 100644 index 213df1b1..00000000 --- a/nw/additions/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -from nw.additions.qconfiglayout import QConfigLayout -from nw.additions.qswitch import QSwitch - -__all__ = [ - "QConfigLayout", - "QSwitch", -] diff --git a/nw/gui/__init__.py b/nw/gui/__init__.py index a39d93ad..c59bfed9 100644 --- a/nw/gui/__init__.py +++ b/nw/gui/__init__.py @@ -1,5 +1,9 @@ # -*- coding: utf-8 -*- +# Qt Additions +from nw.gui.additions.qconfiglayout import QConfigLayout +from nw.gui.additions.qswitch import QSwitch + # Main Window Elements from nw.gui.icons import GuiIcons from nw.gui.mainmenu import GuiMainMenu @@ -33,6 +37,8 @@ from nw.gui.tools.optionstate import OptionState from nw.gui.tools.wordcounter import WordCounter __all__ = [ + "QConfigLayout", + "QSwitch", "GuiIcons", "GuiMainMenu", "GuiMainStatus", diff --git a/nw/gui/additions/__init__.py b/nw/gui/additions/__init__.py new file mode 100644 index 00000000..04f5e25a --- /dev/null +++ b/nw/gui/additions/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from nw.gui.additions.qconfiglayout import QConfigLayout +from nw.gui.additions.qswitch import QSwitch + +__all__ = [ + "QConfigLayout", + "QSwitch", +] diff --git a/nw/additions/qconfiglayout.py b/nw/gui/additions/qconfiglayout.py similarity index 100% rename from nw/additions/qconfiglayout.py rename to nw/gui/additions/qconfiglayout.py diff --git a/nw/additions/qswitch.py b/nw/gui/additions/qswitch.py similarity index 100% rename from nw/additions/qswitch.py rename to nw/gui/additions/qswitch.py diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index 7a6f167b..581d7307 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -38,7 +38,7 @@ from PyQt5.QtWidgets import ( QFileDialog ) -from nw.additions import QSwitch, QConfigLayout +from nw.gui.additions import QSwitch, QConfigLayout from nw.core import NWSpellCheck, NWSpellSimple, NWSpellEnchant from nw.constants import nwAlert, nwQuotes From aea39ba1aadacb402b3c925e30fb3902cf401d11 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 21:33:59 +0200 Subject: [PATCH 8/9] Renamed the textanalyse file --- lib/{text/analyse.py => textanalyse.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/{text/analyse.py => textanalyse.py} (100%) diff --git a/lib/text/analyse.py b/lib/textanalyse.py similarity index 100% rename from lib/text/analyse.py rename to lib/textanalyse.py From 76b4ffe0f24afaaea929284a37ddad0087058ada Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 8 May 2020 21:40:56 +0200 Subject: [PATCH 9/9] Add back some file history from deleted files --- nw/core/tools.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nw/core/tools.py b/nw/core/tools.py index f90ae584..2c96cee6 100644 --- a/nw/core/tools.py +++ b/nw/core/tools.py @@ -7,8 +7,9 @@ File History: Created: 2019-04-22 [0.0.1] countWords - Moved: 2019-05-30 [0.1.4] countWords + Created: 2019-10-13 [0.2.3] numberToWord, _numberToWordEN Created: 2020-02-13 [0.4.3] projectMaintenance + Merged: 2020-05-08 [0.4.5] All of the above into this file This file is a part of novelWriter Copyright 2020, Veronica Berglyd Olsen