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