# -*- coding: utf-8 -*- """novelWriter Text Tokenizer novelWriter – Text Tokenizer ============================== Splits a piece of nW markdown text into its elements File History: Created: 2019-05-05 [0.0.1] """ import textwrap import logging import re import nw from operator import itemgetter from PyQt5.QtCore import QRegularExpression from nw.project.document import NWDoc logger = logging.getLogger(__name__) class Tokenizer(): FMT_B_B = 1 # Begin Bold FMT_B_E = 2 # End Bold FMT_I_B = 3 # Begin Italics FMT_I_E = 4 # End Italics FMT_U_B = 5 # Begin Underline FMT_U_E = 6 # End Underline def __init__(self, theProject, theParent): self.mainConf = nw.CONFIG self.theProject = theProject self.theParent = theParent self.theText = None self.theHandle = None self.theItem = None self.theTokens = None self.theResult = None self.wordWrap = 80 self.doComments = False self.doCommands = False return def setComments(self, doComments): self.doComments = doComments return def setCommands(self, doCommands): self.doCommands = doCommands return def setWordWrap(self, wordWrap): if wordWrap >= 0: self.wordWrap = wordWrap else: self.wordWrap = 0 return def setText(self, theHandle, theText=None): self.theHandle = theHandle self.theItem = self.theProject.getItem(theHandle) if theText is not None: # If the text is set, just use that self.theText = theText else: # Otherwise, load it from file theDocument = NWDoc(self.theProject, self.theParent) self.theText = theDocument.openDocument(theHandle) return def doAutoReplace(self): if len(self.theProject.autoReplace) > 0: repDict = {} for aKey, aVal in self.theProject.autoReplace.items(): repDict["<%s>" % aKey] = aVal xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL) self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText) return def tokenizeText(self): """Scan the text for either lines starting with specific characters that indicate headers, comments, commands etc, or just contains plain text. in the case of plain text, apply the same RegExes that the syntax highlighter uses and save the locations of these formatting tags into the token array. """ # RegExes for adding formatting tags within text lines # Keep in sync with the DocHighlighter class rxFormats = [( QRegularExpression(r"(? 0: tText = textwrap.fill(tText, width=self.wordWrap) # Then the text can receive final formatting before we append it # to the results. We store text bits in a buffer and merge them only # when we find an empty line, indicating a new paragraph if tType == "empty": if len(thisPar) > 0: self.theResult += "%s\n\n" % " ".join(thisPar) thisPar = [] elif tType == "header1": uLine = "="*min(len(tText),self.wordWrap) self.theResult += "%s\n%s\n\n" % (tText,uLine) elif tType == "header2": uLine = "~"*min(len(tText),self.wordWrap) self.theResult += "%s\n%s\n\n" % (tText,uLine) elif tType == "header3": uLine = "-"*min(len(tText),self.wordWrap) self.theResult += "%s\n%s\n\n" % (tText,uLine) elif tType == "header4": self.theResult += "%s\n\n" % tText elif tType == "text": thisPar.append(tText) elif tType == "comment" and self.doComments: self.theResult += "%s\n\n" % tText elif tType == "command" and self.doCommands: self.theResult += "%s\n\n" % tText return # END Class Tokenizer