Use Python regex for spell checking
This commit is contained in:
@@ -23,6 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from re import UNICODE, compile
|
||||||
|
|
||||||
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||||
|
|
||||||
from novelwriter.enum import (
|
from novelwriter.enum import (
|
||||||
@@ -66,6 +68,10 @@ class nwRegEx:
|
|||||||
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:b|i|s|u|m|sup|sub)\])"
|
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:b|i|s|u|m|sup|sub)\])"
|
||||||
FMT_SV = r"(?i)(?<!\\)(\[(?:footnote):)(.+?)(?<!\\)(\])"
|
FMT_SV = r"(?i)(?<!\\)(\[(?:footnote):)(.+?)(?<!\\)(\])"
|
||||||
|
|
||||||
|
RX_WORDS = compile(r"\b([^\s\-\+\/–—\[\]:]+)\b", UNICODE)
|
||||||
|
RX_FMT_SC = compile(r"(?i)(?<!\\)(\[[\/\!]?(?:b|i|s|u|m|sup|sub)\])", UNICODE)
|
||||||
|
RX_FMT_SV = compile(r"(?i)(?<!\\)(\[(?:footnote):)(.+?)(?<!\\)(\])", UNICODE)
|
||||||
|
|
||||||
|
|
||||||
class nwShortcode:
|
class nwShortcode:
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
@@ -44,13 +45,6 @@ from novelwriter.types import QRegExUnicode
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
SPELLRX = QRegularExpression(r"\b[^\s\-\+\/–—\[\]:]+\b")
|
|
||||||
SPELLRX.setPatternOptions(QRegExUnicode)
|
|
||||||
SPELLSC = QRegularExpression(nwRegEx.FMT_SC)
|
|
||||||
SPELLSC.setPatternOptions(QRegExUnicode)
|
|
||||||
SPELLSV = QRegularExpression(nwRegEx.FMT_SV)
|
|
||||||
SPELLSV.setPatternOptions(QRegExUnicode)
|
|
||||||
|
|
||||||
BLOCK_NONE = 0
|
BLOCK_NONE = 0
|
||||||
BLOCK_TEXT = 1
|
BLOCK_TEXT = 1
|
||||||
BLOCK_META = 2
|
BLOCK_META = 2
|
||||||
@@ -427,8 +421,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|||||||
self.setCurrentBlockUserData(data)
|
self.setCurrentBlockUserData(data)
|
||||||
|
|
||||||
if self._spellCheck:
|
if self._spellCheck:
|
||||||
for xPos, xLen in data.spellCheck(text, xOff):
|
for xPos, xEnd in data.spellCheck(text, xOff):
|
||||||
for x in range(xPos, xPos+xLen):
|
for x in range(xPos, xEnd):
|
||||||
cFmt = self.format(x)
|
cFmt = self.format(x)
|
||||||
cFmt.merge(self._spellErr)
|
cFmt.merge(self._spellErr)
|
||||||
self.setFormat(x, 1, cFmt)
|
self.setFormat(x, 1, cFmt)
|
||||||
@@ -492,22 +486,22 @@ class TextBlockData(QTextBlockUserData):
|
|||||||
"""
|
"""
|
||||||
if "[" in text:
|
if "[" in text:
|
||||||
# Strip shortcodes
|
# Strip shortcodes
|
||||||
for rX in [SPELLSC, SPELLSV]:
|
for rX in [nwRegEx.RX_FMT_SC, nwRegEx.RX_FMT_SV]:
|
||||||
rxItt = rX.globalMatch(text, offset)
|
for match in re.finditer(rX, text[offset:]):
|
||||||
while rxItt.hasNext():
|
iS = match.start(0) + offset
|
||||||
rxMatch = rxItt.next()
|
iE = match.end(0) + offset
|
||||||
xPos = rxMatch.capturedStart(0)
|
if iS >= 0 and iE >= 0:
|
||||||
xLen = rxMatch.capturedLength(0)
|
text = text[:iS] + " "*(iE - iS) + text[iE:]
|
||||||
xEnd = rxMatch.capturedEnd(0)
|
|
||||||
text = text[:xPos] + " "*xLen + text[xEnd:]
|
|
||||||
|
|
||||||
self._spellErrors = []
|
self._spellErrors = []
|
||||||
rxSpell = SPELLRX.globalMatch(text.replace("_", " "), offset)
|
checker = SHARED.spelling
|
||||||
while rxSpell.hasNext():
|
for match in re.finditer(nwRegEx.RX_WORDS, text[offset:].replace("_", " ")):
|
||||||
rxMatch = rxSpell.next()
|
if (
|
||||||
if not SHARED.spelling.checkWord(rxMatch.captured(0)):
|
(word := match.group(0))
|
||||||
if not rxMatch.captured(0).isnumeric() and not rxMatch.captured(0).isupper():
|
and (iS := match.start(0)) >= 0
|
||||||
self._spellErrors.append(
|
and (iE := match.end(0)) >= 0
|
||||||
(rxMatch.capturedStart(0), rxMatch.capturedLength(0))
|
and not (word.isnumeric() or word.isupper() or checker.checkWord(word))
|
||||||
)
|
):
|
||||||
|
self._spellErrors.append((iS + offset, iE + offset))
|
||||||
|
|
||||||
return self._spellErrors
|
return self._spellErrors
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ class GuiTextDocument(QTextDocument):
|
|||||||
text = block.text()
|
text = block.text()
|
||||||
check = pos - block.position()
|
check = pos - block.position()
|
||||||
if check >= 0:
|
if check >= 0:
|
||||||
for cPos, cLen in data.spellErrors:
|
for cPos, cEnd in data.spellErrors:
|
||||||
cEnd = cPos + cLen
|
cLen = cEnd - cPos
|
||||||
if cPos <= check <= cEnd:
|
if cPos <= check <= cEnd:
|
||||||
word = text[cPos:cEnd]
|
word = text[cPos:cEnd]
|
||||||
return word, cPos, cLen, SHARED.spelling.suggestWords(word)
|
return word, cPos, cLen, SHARED.spelling.suggestWords(word)
|
||||||
|
|||||||
Reference in New Issue
Block a user