Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a dialogue parser #2079

Merged
merged 7 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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