Skip to content

Commit

Permalink
Add a dialogue parser, and horizontal bar auto-complete (#2079)
Browse files Browse the repository at this point in the history
  • Loading branch information
vkbo authored Nov 1, 2024
2 parents 057fc10 + 82e923b commit 1b509ad
Show file tree
Hide file tree
Showing 16 changed files with 443 additions and 231 deletions.
2 changes: 1 addition & 1 deletion novelwriter/core/docbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def _setupBuild(self, bldObj: Tokenizer) -> dict:
bldObj.setJustify(self._build.getBool("format.justifyText"))
bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks"))
bldObj.setDialogueHighlight(self._build.getBool("format.showDialogue"))
bldObj.setDialogHighlight(self._build.getBool("format.showDialogue"))
bldObj.setFirstLineIndent(
self._build.getBool("format.firstLineIndent"),
self._build.getFloat("format.firstIndentWidth"),
Expand Down
20 changes: 10 additions & 10 deletions novelwriter/dialogs/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
)

from novelwriter import CONFIG, SHARED
from novelwriter.common import describeFont, uniqueCompact
from novelwriter.common import compact, describeFont, uniqueCompact
from novelwriter.constants import nwUnicode
from novelwriter.dialogs.quotes import GuiQuoteSelect
from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
Expand Down Expand Up @@ -133,7 +133,7 @@ def buildForm(self) -> None:
"""Build the settings form."""
section = 0
iSz = SHARED.theme.baseIconSize
boxFixed = 5*SHARED.theme.textNWidth
boxFixed = 6*SHARED.theme.textNWidth
minWidth = CONFIG.pxInt(200)
fontWidth = CONFIG.pxInt(162)

Expand Down Expand Up @@ -568,13 +568,13 @@ def buildForm(self) -> None:
)

self.dialogLine = QLineEdit(self)
self.dialogLine.setMaxLength(1)
self.dialogLine.setMaxLength(4)
self.dialogLine.setFixedWidth(boxFixed)
self.dialogLine.setAlignment(QtAlignCenter)
self.dialogLine.setText(CONFIG.dialogLine)
self.mainForm.addRow(
self.tr("Dialogue line symbol"), self.dialogLine,
self.tr("Lines starting with this symbol are dialogue.")
self.tr("Dialogue line symbols"), self.dialogLine,
self.tr("Lines starting with these symbols are always dialogue.")
)

self.narratorBreak = QLineEdit(self)
Expand All @@ -583,8 +583,8 @@ def buildForm(self) -> None:
self.narratorBreak.setAlignment(QtAlignCenter)
self.narratorBreak.setText(CONFIG.narratorBreak)
self.mainForm.addRow(
self.tr("Dialogue narrator break symbol"), self.narratorBreak,
self.tr("Symbol to indicate injected narrator break.")
self.tr("Alternating dialogue/narration symbol"), self.narratorBreak,
self.tr("Alternates dialogue highlighting within a paragraph.")
)

self.highlightEmph = NSwitch(self)
Expand Down Expand Up @@ -953,9 +953,9 @@ def _doSave(self) -> None:
dialogueStyle = self.dialogStyle.currentData()
allowOpenDial = self.allowOpenDial.isChecked()
narratorBreak = self.narratorBreak.text().strip()
dialogueLine = self.dialogLine.text().strip()
altDialogOpen = self.altDialogOpen.text()
altDialogClose = self.altDialogClose.text()
dialogueLine = uniqueCompact(self.dialogLine.text())
altDialogOpen = compact(self.altDialogOpen.text())
altDialogClose = compact(self.altDialogClose.text())
highlightEmph = self.highlightEmph.isChecked()
showMultiSpaces = self.showMultiSpaces.isChecked()

Expand Down
59 changes: 18 additions & 41 deletions novelwriter/formats/tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
from novelwriter.formats.shared import (
BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt
)
from novelwriter.text.patterns import REGEX_PATTERNS
from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -199,9 +199,10 @@ def __init__(self, project: NWProject) -> None:
}

# Dialogue
self._rxDialogue: list[tuple[re.Pattern, tuple[int, str], tuple[int, str]]] = []
self._dialogLine = ""
self._narratorBreak = ""
self._hlightDialog = False
self._rxAltDialog = REGEX_PATTERNS.altDialogStyle
self._dialogParser = DialogParser()
self._dialogParser.initParser()

return

Expand Down Expand Up @@ -335,22 +336,9 @@ def setJustify(self, state: bool) -> None:
self._doJustify = state
return

def setDialogueHighlight(self, state: bool) -> None:
def setDialogHighlight(self, state: bool) -> None:
"""Enable or disable dialogue highlighting."""
self._rxDialogue = []
if state:
if CONFIG.dialogStyle > 0:
self._rxDialogue.append((
REGEX_PATTERNS.dialogStyle,
(TextFmt.COL_B, "dialog"), (TextFmt.COL_E, ""),
))
if CONFIG.altDialogOpen and CONFIG.altDialogClose:
self._rxDialogue.append((
REGEX_PATTERNS.altDialogStyle,
(TextFmt.COL_B, "altdialog"), (TextFmt.COL_E, ""),
))
self._dialogLine = CONFIG.dialogLine.strip()[:1]
self._narratorBreak = CONFIG.narratorBreak.strip()[:1]
self._hlightDialog = state
return

def setTitleMargins(self, upper: float, lower: float) -> None:
Expand Down Expand Up @@ -1132,10 +1120,8 @@ def _extractFormats(

# Match URLs
for res in REGEX_PATTERNS.url.finditer(text):
s = res.start(0)
e = res.end(0)
temp.append((s, s, TextFmt.HRF_B, res.group(0)))
temp.append((e, e, TextFmt.HRF_E, ""))
temp.append((res.start(0), 0, TextFmt.HRF_B, res.group(0)))
temp.append((res.end(0), 0, TextFmt.HRF_E, ""))

# Match Shortcodes
for res in REGEX_PATTERNS.shortcodePlain.finditer(text):
Expand All @@ -1156,24 +1142,15 @@ def _extractFormats(
))

# Match Dialogue
if self._rxDialogue and hDialog:
for regEx, (fmtB, clsB), (fmtE, clsE) in self._rxDialogue:
for res in regEx.finditer(text):
temp.append((res.start(0), 0, fmtB, clsB))
temp.append((res.end(0), 0, fmtE, clsE))

if self._dialogLine and text.startswith(self._dialogLine):
if self._narratorBreak:
pos = 0
for num, bit in enumerate(text[1:].split(self._narratorBreak), 1):
length = len(bit) + 1
if num%2:
temp.append((pos, 0, TextFmt.COL_B, "dialog"))
temp.append((pos + length, 0, TextFmt.COL_E, ""))
pos += length
else:
temp.append((0, 0, TextFmt.COL_B, "dialog"))
temp.append((len(text), 0, TextFmt.COL_E, ""))
if self._hlightDialog and hDialog:
if self._dialogParser.enabled:
for pos, end in self._dialogParser(text):
temp.append((pos, 0, TextFmt.COL_B, "dialog"))
temp.append((end, 0, TextFmt.COL_E, ""))
if self._rxAltDialog:
for res in self._rxAltDialog.finditer(text):
temp.append((res.start(0), 0, TextFmt.COL_B, "altdialog"))
temp.append((res.end(0), 0, TextFmt.COL_E, ""))

# Post-process text and format
result = text
Expand Down
Loading

0 comments on commit 1b509ad

Please sign in to comment.