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

Allow inserting characters in manuscript headers #1677

Merged
merged 13 commits into from
Jan 31, 2024
Merged
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
5 changes: 5 additions & 0 deletions docs/source/int_customise.rst
Original file line number Diff line number Diff line change
@@ -174,6 +174,7 @@ A syntax theme ``.conf`` file consists of the following settings:
shortcode = 0, 0, 0
keyword = 0, 0, 0
value = 0, 0, 0
optional = 0, 0, 0
spellcheckline = 0, 0, 0
errorline = 0, 0, 0
replacetag = 0, 0, 0
@@ -186,3 +187,7 @@ to black, except ``background`` which defaults to white,
.. versionadded:: 2.2
The `shortcode` syntax colour entry was added, so you need to update your custom themes if you
made any before version 2.2.

.. versionadded:: 2.3
The `optional` syntax colour entry was added, so you need to update your custom themes if you
made any before version 2.3.
50 changes: 35 additions & 15 deletions docs/source/project_references.rst
Original file line number Diff line number Diff line change
@@ -47,16 +47,28 @@ How to Use Tags
===============

A "tag" in novelWriter is a word or phrase that you define as belonging to a heading. Tags are set
by using the ``@tags`` :term:`keyword`. The full format of a tag is ``@tag: tagname``, where
``tagname`` is an identifier of your choosing. You can only set *one* tag per heading, and the tag
has to be unique across all documents in the project.
by using the ``@tags`` :term:`keyword`.

.. versionadded:: 2.2
Tags are now case insensitive.
The general format of a tag is ``@tag: tagName``.

The full format of a tag is ``@tag: tagName | displayName``.

``tagName`` (Required)
This is a unique identifier of your choosing. It is the value you use later for making
references back to this document, or section of the document.

``displayName`` (Optional)
This is an optional display name used for the tag. When you build your manuscript, you can for
instance insert the point of view character name into chapter headings. By default, the
``tagName`` value is used in headings, but if you use a shortened format internally in your
project, you can use this to specify a more suitable format for your manuscript.

After the tags have been defined, they can then be referenced in the novel documents, or
cross-referenced in other notes. they will also show up in the :guilabel:`Outline View` and in the
back-reference panel when a document is opened in the viewer.
You can only set *one* tag per heading, and the tag has to be unique across *all* documents in the
project.

After a tag has been defined, it can be referenced in novel documents, or cross-referenced in other
notes. Tags will also show up in the :guilabel:`Outline View` and in the back-reference panel when
a document is opened in the viewer.

The syntax highlighter will indicate to you that the keyword is correctly used and that the tag is
allowed, that is, the tag is unique. Duplicate tags should be detected as long as the index is up
@@ -68,22 +80,30 @@ there for you to use in whatever way you wish. Of course, the content of the doc
to the manuscript, or an outline document. If you want to compile a single document of all your
notes, you can do this from the :guilabel:`Manuscript Build` tool.

.. versionadded:: 2.2
Tags are no longer case sensitive. The tags are by default displayed with the capitalisation you
use when defining the tag, but you don't have to use the same capitalisation when referencing
it later.

.. versionadded:: 2.3
Tags can have an optional display name for manuscript builds.

Example of a heading with a tag for a character of the story:

.. code-block:: none
# Jane Doe
# Character: Jane Doe
@tag: Jane
@tag: Jane | Jane Doe
Some information about the character Jane Doe.
When this is done in a document in a :term:`Root Folder` of type "Characters", the tag is
automatically treated as an available character in your project, and you will be able to reference
it in any of your other documents using the reference keywords for characters. It will also show up
in the Character tab in the Reference panel below the document viewer, and in the reference
auto-completer menu in the editor when you fill in references. See :ref:`a_ui_view` and
:ref:`a_references_completer`.
automatically treated as an available character in your project with the value "Jane", and you will
be able to reference it in any of your other documents using the reference keywords for characters.
It will also show up in the Character tab in the Reference panel below the document viewer, and in
the reference auto-completer menu in the editor when you fill in references. See :ref:`a_ui_view`
and :ref:`a_references_completer`.

It is the root folder type that defines what category of story elements the tag is indexed under.
See the :ref:`a_proj_roots` section for an overview of available root folder types. They are also
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/default_dark.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 150, 150, 150
shortcode = 0, 155, 200
keyword = 200, 46, 0
value = 184, 200, 0
optional = 0, 155, 200
spellcheckline = 200, 46, 0
errorline = 46, 200, 0
replacetag = 0, 184, 46
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/default_light.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 100, 100, 100
shortcode = 0, 100, 0
keyword = 200, 50, 50
value = 50, 150, 50
optional = 0, 100, 0
spellcheckline = 200, 0, 0
errorline = 0, 150, 0
replacetag = 0, 150, 0
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/grey_dark.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 150, 150, 150
shortcode = 225, 225, 225
keyword = 225, 225, 225
value = 200, 200, 200
optional = 225, 225, 225
spellcheckline = 200, 46, 0
errorline = 46, 200, 0
replacetag = 225, 225, 225
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/grey_light.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 100, 100, 100
shortcode = 0, 0, 0
keyword = 0, 0, 0
value = 20, 20, 20
optional = 0, 0, 0
spellcheckline = 200, 0, 0
errorline = 0, 150, 0
replacetag = 0, 0, 0
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/light_owl.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 152, 159, 177
shortcode = 40, 142, 215
keyword = 222, 61, 58
value = 150, 74, 193
optional = 40, 142, 215
spellcheckline = 222, 61, 58
errorline = 8, 145, 106
replacetag = 42, 162, 152
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/night_owl.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 99, 119, 119
shortcode = 130, 170, 255
keyword = 247, 140, 108
value = 199, 146, 234
optional = 130, 170, 255
spellcheckline = 247, 140, 108
errorline = 173, 219, 103
replacetag = 127, 219, 202
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/solarized_dark.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 147, 161, 161
shortcode = 147, 161, 161
keyword = 133, 153, 0
value = 203, 75, 22
optional = 147, 161, 161
spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/solarized_light.conf
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ hidden = 88, 110, 117
shortcode = 88, 110, 117
keyword = 133, 153, 0
value = 203, 75, 22
optional = 88, 110, 117
spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/tomorrow.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 142, 144, 140
shortcode = 66, 113, 174
keyword = 240, 40, 41
value = 137, 89, 168
optional = 66, 113, 174
spellcheckline = 240, 40, 41
errorline = 113, 140, 0
replacetag = 62, 153, 159
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/tomorrow_night.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 150, 152, 150
shortcode = 129, 162, 190
keyword = 204, 102, 102
value = 178, 148, 187
optional = 129, 162, 190
spellcheckline = 204, 102, 102
errorline = 181, 189, 104
replacetag = 138, 190, 183
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/tomorrow_night_blue.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 114, 133, 183
shortcode = 187, 218, 255
keyword = 255, 157, 164
value = 235, 187, 255
optional = 187, 218, 255
spellcheckline = 255, 157, 164
errorline = 209, 241, 169
replacetag = 153, 255, 255
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/tomorrow_night_bright.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 150, 152, 150
shortcode = 122, 166, 218
keyword = 213, 78, 83
value = 195, 151, 216
optional = 122, 166, 218
spellcheckline = 213, 78, 83
errorline = 185, 202, 74
replacetag = 112, 192, 177
1 change: 1 addition & 0 deletions novelwriter/assets/syntax/tomorrow_night_eighties.conf
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ hidden = 153, 153, 153
shortcode = 102, 153, 204
keyword = 242, 119, 122
value = 204, 153, 204
optional = 102, 153, 204
spellcheckline = 242, 119, 122
errorline = 153, 204, 153
replacetag = 102, 204, 204
33 changes: 13 additions & 20 deletions novelwriter/common.py
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
import unicodedata
import xml.etree.ElementTree as ET

from typing import Any, Literal
from typing import TYPE_CHECKING, Any, Literal
from pathlib import Path
from datetime import datetime
from configparser import ConfigParser
@@ -43,6 +43,9 @@
from novelwriter.error import logException
from novelwriter.constants import nwConst, nwUnicode

if TYPE_CHECKING: # pragma: no cover
from typing import TypeGuard # Requires Python 3.10

logger = logging.getLogger(__name__)


@@ -104,15 +107,6 @@ def checkBool(value: Any, default: bool) -> bool:
return default


def checkHandle(value, default, allowNone=False):
"""Check if a value is a handle."""
if allowNone and (value is None or value == "None"):
return None
if isHandle(value):
return str(value)
return default


def checkUuid(value: Any, default: str) -> str:
"""Try to process a value as an UUID, or return a default."""
try:
@@ -135,7 +129,7 @@ def checkPath(value: Any, default: Path) -> Path:
# Validator Functions
##

def isHandle(value: Any) -> bool:
def isHandle(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid novelWriter handle.
Note: This is case sensitive. Must be lower case!
"""
@@ -149,7 +143,7 @@ def isHandle(value: Any) -> bool:
return True


def isTitleTag(value: Any) -> bool:
def isTitleTag(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid title tag string."""
if not isinstance(value, str):
return False
@@ -163,19 +157,19 @@ def isTitleTag(value: Any) -> bool:
return True


def isItemClass(value: str) -> bool:
def isItemClass(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid nwItemClass identifier."""
return value in nwItemClass.__members__
return isinstance(value, str) and value in nwItemClass.__members__


def isItemType(value: str) -> bool:
def isItemType(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid nwItemType identifier."""
return value in nwItemType.__members__
return isinstance(value, str) and value in nwItemType.__members__


def isItemLayout(value: str) -> bool:
def isItemLayout(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid nwItemLayout identifier."""
return value in nwItemLayout.__members__
return isinstance(value, str) and value in nwItemLayout.__members__


def hexToInt(value: Any, default: int = 0) -> int:
@@ -189,8 +183,7 @@ def hexToInt(value: Any, default: int = 0) -> int:


def minmax(value: int, minVal: int, maxVal: int) -> int:
"""Make sure an integer is between min and max value (inclusive).
"""
"""Check that an value is between min and max value (inclusive)."""
return min(maxVal, max(minVal, value))


25 changes: 15 additions & 10 deletions novelwriter/constants.py
Original file line number Diff line number Diff line change
@@ -300,16 +300,21 @@ class nwLabels:

class nwHeadFmt:

BR = "{BR}"
TITLE = "{Title}"
CH_NUM = "{Chapter}"
CH_WORD = "{Chapter:Word}"
CH_ROMU = "{Chapter:URoman}"
CH_ROML = "{Chapter:LRoman}"
SC_NUM = "{Scene}"
SC_ABS = "{Scene:Abs}"

PAGE_HEADERS = [TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS]
BR = "{BR}"
TITLE = "{Title}"
CH_NUM = "{Chapter}"
CH_WORD = "{Chapter:Word}"
CH_ROMU = "{Chapter:URoman}"
CH_ROML = "{Chapter:LRoman}"
SC_NUM = "{Scene}"
SC_ABS = "{Scene:Abs}"
CHAR_POV = "{Char:POV}"
CHAR_FOCUS = "{Char:Focus}"

PAGE_HEADERS = [
TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS,
CHAR_POV, CHAR_FOCUS
]

# ODT Document Page Header
ODT_PROJECT = "{Project}"
Loading