diff --git a/novelwriter/formats/shared.py b/novelwriter/formats/shared.py index f097e99a..170ee890 100644 --- a/novelwriter/formats/shared.py +++ b/novelwriter/formats/shared.py @@ -87,10 +87,12 @@ class TextFmt(IntEnum): COL_E = 16 # End colour ANM_B = 17 # Begin anchor name ANM_E = 18 # End anchor name - HRF_B = 19 # Begin href link - HRF_E = 20 # End href link - FNOTE = 21 # Footnote marker - STRIP = 22 # Strip the format code + ARF_B = 19 # Begin anchor link + ARF_E = 20 # End anchor link + HRF_B = 21 # Begin href link + HRF_E = 22 # End href link + FNOTE = 23 # Footnote marker + STRIP = 24 # Strip the format code class BlockTyp(IntEnum): diff --git a/novelwriter/formats/tohtml.py b/novelwriter/formats/tohtml.py index 2f8be4ce..484a48ee 100644 --- a/novelwriter/formats/tohtml.py +++ b/novelwriter/formats/tohtml.py @@ -49,6 +49,7 @@ HTML_OPENER: dict[int, tuple[int, str]] = { TextFmt.SUB_B: (TextFmt.SUB_E, ""), TextFmt.COL_B: (TextFmt.COL_E, ""), TextFmt.ANM_B: (TextFmt.ANM_E, ""), + TextFmt.ARF_B: (TextFmt.ARF_E, ""), TextFmt.HRF_B: (TextFmt.HRF_E, ""), } @@ -63,6 +64,7 @@ HTML_CLOSER: dict[int, tuple[int, str]] = { TextFmt.SUB_E: (TextFmt.SUB_B, ""), TextFmt.COL_E: (TextFmt.COL_B, ""), TextFmt.ANM_E: (TextFmt.ANM_B, ""), + TextFmt.ARF_E: (TextFmt.ARF_B, ""), TextFmt.HRF_E: (TextFmt.HRF_B, ""), } @@ -398,7 +400,7 @@ class ToHtml(Tokenizer): if not state.get(fmt, True): if fmt == TextFmt.COL_B and (color := self._classes.get(data)): tags.append((pos, m[1].format(color.name(QtHexRgb)))) - elif fmt in (TextFmt.ANM_B, TextFmt.HRF_B): + elif fmt in (TextFmt.ANM_B, TextFmt.ARF_B, TextFmt.HRF_B): tags.append((pos, m[1].format(data or "#"))) else: tags.append((pos, m[1])) diff --git a/novelwriter/formats/tokenizer.py b/novelwriter/formats/tokenizer.py index 3ae28f63..615b3237 100644 --- a/novelwriter/formats/tokenizer.py +++ b/novelwriter/formats/tokenizer.py @@ -1089,8 +1089,8 @@ class Tokenizer(ABC): for n, bit in enumerate(bits[1:], 2): end = pos + len(bit) fmt.append((pos, TextFmt.COL_B, "tag")) - fmt.append((pos, TextFmt.HRF_B, f"#tag_{bit}".lower())) - fmt.append((end, TextFmt.HRF_E, "")) + fmt.append((pos, TextFmt.ARF_B, f"#tag_{bit}".lower())) + fmt.append((end, TextFmt.ARF_E, "")) fmt.append((end, TextFmt.COL_E, "")) txt.append(bit) pos = end diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index 838ffb9f..653e8207 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -330,12 +330,12 @@ class ToQTextDocument(Tokenizer): cFmt.setAnchorNames([data]) elif fmt == TextFmt.ANM_E: cFmt.setAnchor(False) - elif fmt == TextFmt.HRF_B: + elif fmt in (TextFmt.HRF_B, TextFmt.ARF_B): cFmt.setForeground(primary or self._theme.link) cFmt.setFontUnderline(True) cFmt.setAnchor(True) cFmt.setAnchorHref(data) - elif fmt == TextFmt.HRF_E: + elif fmt in (TextFmt.HRF_E, TextFmt.ARF_E): cFmt.setForeground(primary or self._theme.text) cFmt.setFontUnderline(False) cFmt.setAnchor(False) diff --git a/sample/content/636b6aa9b697b.nwd b/sample/content/636b6aa9b697b.nwd index c03c1cc2..ec7fca24 100644 --- a/sample/content/636b6aa9b697b.nwd +++ b/sample/content/636b6aa9b697b.nwd @@ -1,8 +1,8 @@ %%~name: Making a Scene %%~path: 6a2d6d5f4f401/636b6aa9b697b %%~kind: NOVEL/DOCUMENT -%%~hash: 349d9ce3d59ad241d63b01380c53a7fb26ce9f19 -%%~date: Unknown/2024-10-24 23:44:27 +%%~hash: 89d562ae05727028d74bd10cfd6953882d1cd140 +%%~date: Unknown/2024-10-25 12:41:02 ### Making a Scene @pov: Jane @@ -20,6 +20,8 @@ In addition, the editor supports automatic formatting of “quotes”, both doub If you have the need for it, you can also add text that can be automatically replaced by other text when you generate a preview or export the project. Now, let’s auto-replace this A with , and this C with . While is just . Press Ctrl+R to see what this looks like in the view pane. The list of auto-replaced text is set in Project Settings. +You can also add URLs like http://www.example.com to the text. + The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported – and can be automatically inserted when typing two hyphens. Thin spaces and thin non-breaking spaces are also supported from the Insert menu, and can be used to separate numbers from their units, like: 25 kg.[footnote:f4xr5] diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx index 3796c43a..decdea2f 100644 --- a/sample/nwProject.nwx +++ b/sample/nwProject.nwx @@ -1,6 +1,6 @@ - - + + Sample Project Jane Smith @@ -36,7 +36,7 @@ Main - + Novel @@ -58,11 +58,11 @@ Chapter One - + Making a Scene - + Another Scene @@ -102,7 +102,7 @@ Main Characters - + John Smith diff --git a/tests/test_formats/test_fmt_tokenizer.py b/tests/test_formats/test_fmt_tokenizer.py index 1a7691e5..ab75254f 100644 --- a/tests/test_formats/test_fmt_tokenizer.py +++ b/tests/test_formats/test_fmt_tokenizer.py @@ -834,8 +834,8 @@ def testFmtToken_MetaFormat(mockGUI): BlockTyp.KEYWORD, "char", "Characters: Bod", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (11, TextFmt.COL_E, ""), (11, TextFmt.B_E, ""), - (12, TextFmt.COL_B, "tag"), (12, TextFmt.HRF_B, "#tag_bod"), - (15, TextFmt.HRF_E, ""), (15, TextFmt.COL_E, ""), + (12, TextFmt.COL_B, "tag"), (12, TextFmt.ARF_B, "#tag_bod"), + (15, TextFmt.ARF_E, ""), (15, TextFmt.COL_E, ""), ], BlockFmt.NONE )] assert tokens._raw[-1] == "@char: Bod\n\n" @@ -846,22 +846,22 @@ def testFmtToken_MetaFormat(mockGUI): BlockTyp.KEYWORD, "pov", "Point of View: Bod", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (14, TextFmt.COL_E, ""), (14, TextFmt.B_E, ""), - (15, TextFmt.COL_B, "tag"), (15, TextFmt.HRF_B, "#tag_bod"), - (18, TextFmt.HRF_E, ""), (18, TextFmt.COL_E, ""), + (15, TextFmt.COL_B, "tag"), (15, TextFmt.ARF_B, "#tag_bod"), + (18, TextFmt.ARF_E, ""), (18, TextFmt.COL_E, ""), ], BlockFmt.Z_BTM ), ( BlockTyp.KEYWORD, "plot", "Plot: Main", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (5, TextFmt.COL_E, ""), (5, TextFmt.B_E, ""), - (6, TextFmt.COL_B, "tag"), (6, TextFmt.HRF_B, "#tag_main"), - (10, TextFmt.HRF_E, ""), (10, TextFmt.COL_E, ""), + (6, TextFmt.COL_B, "tag"), (6, TextFmt.ARF_B, "#tag_main"), + (10, TextFmt.ARF_E, ""), (10, TextFmt.COL_E, ""), ], BlockFmt.Z_TOP | BlockFmt.Z_BTM ), ( BlockTyp.KEYWORD, "location", "Locations: Europe", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (10, TextFmt.COL_E, ""), (10, TextFmt.B_E, ""), - (11, TextFmt.COL_B, "tag"), (11, TextFmt.HRF_B, "#tag_europe"), - (17, TextFmt.HRF_E, ""), (17, TextFmt.COL_E, ""), + (11, TextFmt.COL_B, "tag"), (11, TextFmt.ARF_B, "#tag_europe"), + (17, TextFmt.ARF_E, ""), (17, TextFmt.COL_E, ""), ], BlockFmt.Z_TOP )] assert tokens._raw[-1] == "@pov: Bod\n@plot: Main\n@location: Europe\n\n" @@ -874,8 +874,8 @@ def testFmtToken_MetaFormat(mockGUI): BlockTyp.KEYWORD, "pov", "Point of View: Bod", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (14, TextFmt.COL_E, ""), (14, TextFmt.B_E, ""), - (15, TextFmt.COL_B, "tag"), (15, TextFmt.HRF_B, "#tag_bod"), - (18, TextFmt.HRF_E, ""), (18, TextFmt.COL_E, ""), + (15, TextFmt.COL_B, "tag"), (15, TextFmt.ARF_B, "#tag_bod"), + (18, TextFmt.ARF_E, ""), (18, TextFmt.COL_E, ""), ], BlockFmt.NONE )] @@ -1831,10 +1831,10 @@ def testFmtToken_FormatMeta(mockGUI): "@char", "Characters: Jane, John", [ (0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "keyword"), (11, TextFmt.COL_E, ""), (11, TextFmt.B_E, ""), - (12, TextFmt.COL_B, "tag"), (12, TextFmt.HRF_B, "#tag_jane"), - (16, TextFmt.HRF_E, ""), (16, TextFmt.COL_E, ""), - (18, TextFmt.COL_B, "tag"), (18, TextFmt.HRF_B, "#tag_john"), - (22, TextFmt.HRF_E, ""), (22, TextFmt.COL_E, ""), + (12, TextFmt.COL_B, "tag"), (12, TextFmt.ARF_B, "#tag_jane"), + (16, TextFmt.ARF_E, ""), (16, TextFmt.COL_E, ""), + (18, TextFmt.COL_B, "tag"), (18, TextFmt.ARF_B, "#tag_john"), + (22, TextFmt.ARF_E, ""), (22, TextFmt.COL_E, ""), ] )