Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Fixes variables within hyperlinks

AuthorDaveJarvis <email>
Date2025-09-03 19:42:27 GMT-0700
Commit91741f36c3381fa59cf71dff781e0535ce983fbb
Parentbdd99ed
docs/02-installation.md
+# Installation
+
+This chapter covers installing the application and its dependencies, including
+the typesetting software required for PDF generation. Installation can be done
+using a guided wizard or manually by following platform-specific steps.
+
+## Automatic
+
+The application uses the ConTeXt typesetting system, the podman container
+manager, various themes, and numerous fonts to produce high-quality PDF files.
+Using a container reduces the number of manual installation steps.
+
+When exporting a document to a PDF file for the first time, a wizard will guide
+you through the installation process. These steps will differ depending on the
+operating system.
+
+Launch the installation wizard as follows:
+
+1. Start {{app.title}}.
+1. Click **File → Export As → PDF**.
+
+Use the wizard to install the requisite software and typesetting themes.
+
+## Manual
+
+For users who prefer more control over, and a deeper understanding of, the
+installation process, manual setup involves downloading and configuring the
+typesetting software according to your operating system's requirements.
+
+Download the typesetting software as follows:
+
+1. Start {{app.title}}.
+1. Click **File → Export As → PDF**.
+1. Note the following details (e.g., Windows X86 64-bit):
+ * operating system name;
+ * instruction set; and
+ * architecture.
+1. Click the [link](https://wiki.contextgarden.net/Introduction/Installation) in the dialog.
+1. Download the appropriate archive file.
+
+Follow the steps that apply to the computer's operating system:
+
+* [Unix](#unix) (includes MacOS, FreeBSD, Linux, and similar)
+* [Windows](#windows) (includes Windows 7, Windows 10, and similar)
+
+### Unix
+
+On Linux, MacOS, FreeBSD, and similar operating systems, proceed as follows:
+
+1. Open a terminal.
+1. Run the following commands (change `LOCAL_FILE` to suit):
+
+ ``` bash
+ export LOCAL_DIR=.local/bin/context
+ export LOCAL_FILE=context-linuxmusl-64.zip
+ export CONTEXT_DIR="${HOME}/${LOCAL_DIR}"
+ mkdir -p "${CONTEXT_DIR}"
+ cd "${CONTEXT_DIR}"
+ wget "https://lmtx.pragma-ade.nl/install-lmtx/${LOCAL_FILE}"
+ unzip ${LOCAL_FILE}
+ rm ${LOCAL_FILE}
+ chmod +x install.sh
+ ./install.sh
+ echo export CONTEXT_DIR=\"\${HOME}/${LOCAL_DIR}" \
+ >> ${HOME}/.bashrc
+ echo PATH="\"\${PATH}:\${CONTEXT_DIR}/tex/texmf-linux-64/bin\"" \
+ >> ${HOME}/.bashrc
+ source ${HOME}/.bashrc
+ ```
+
+### Windows
+
+On a Windows operating system, install the typesetting software as follows:
+
+1. Extract the `.zip` file into `C:\Users\%USERNAME%\AppData\Local\context` (the "root" directory).
+1. Run **install.bat** to download and install the software.
+ * If prompted, click **Run anyway** (or click **More info** first).
+1. Download [localpath.bat]({{install.windows.batch}}).
+1. Save the file to the typesetting software's "root" directory.
+1. Rename `localpath.bat.txt` to `localpath.bat`, if necessary.
+1. Run `localpath.bat` (to set and save the `PATH` environment variable).
+
+## Verification
+
+After completing the installation process, it's important to verify that the
+typesetting software has been installed correctly and is accessible from the
+command line.
+
+Verify the installation is complete as follows:
+
+1. Open a new terminal or command prompt.
+1. Type: `context --version`
+1. Press [⏎ Enter]{.kbd}.
+
+If version information is displayed then the software is installed correctly.
+
+## Theme packs
+
+Theme packs define the visual appearance and styling of typeset documents.
+Installing and configuring theme packs is essential for producing high-quality
+PDF files. Each theme has its own requirements.
+
+### Install theme pack
+
+Install and configure the theme pack as follows:
+
+1. Download the [theme-pack.zip](https://gitlab.com/DaveJarvis/keenwrite-themes/-/releases/permalink/latest/downloads/theme-pack.zip) archive.
+1. Extract archive into a known location.
+1. Start {{app.title}}, if not already running.
+1. Click **Edit → Preferences**.
+1. Click **Typesetting**.
+1. Click **Browse** beside **Themes**.
+1. Navigate to the `themes` directory.
+1. Click **Open**.
+1. Click **OK**.
+
+The theme pack is installed.
+
+### Configure theme
+
+Once a theme pack is installed, additional configuration may be required based
+on the theme's formatting needs. Configure individual themes based on their
+specific requirements.
+
+For example, the _Boschet_ theme requires downloading and installing specific font families, which include:
+
+* [Inconsolata]({{fonts.url}}/inconsolata.zip)
+* [Libre Baskerville]({{fonts.url}}/libre-baskerville.zip)
+* [Niconne]({{fonts.url}}/niconne.zip)
+* [Open Sans Emoji]({{fonts.url}}open-sans-emoji.zip)
+* [Source Serif 4]({{fonts.url}}/source-serif-4.zip)
+* [TW Kai]({{fonts.url}}/tw-kai.zip)
+* [Underwood Quiet Tab]({{fonts.url}}/underwood.zip)
+
+See your operating system instructions for how to install a font.
+
docs/03-quick-start.md
+# Quick start
+
+This chapter provides a brief overview of how to use the editor.
+
+## First document
+
+Create and open a document as follows:
+
+1. Start {{app.title}}.
+1. Click **File → Save As** to save the untitled file.
+1. Set the file name to: `metadata.yaml`
+1. Save the (empty) file.
+1. Click **File → Open** to load the variable definition file.
+1. Change **Source Files** to **Variable Files** to list variable definition files.
+1. Browse to and select the `.yaml`.
+1. Click **Open**.
+
+The variable definitions appear in the variable definition tab under the heading of **Variables**.
+
+## Basic syntax
+
+The editor supports standard Markdown features listed in [@tbl:markdown-syntax-basic]. While editing, try the toolbar icons to see how formatting appears in the preview tab.
+
+| Style | Syntax |
+|--------------------|---------------------------|
+| **Bold** | `**bold**` |
+| *Italic* | `*italic*` |
+| ~~Struck text~~ | `~~struck~~` |
+| Horizontal rule | `---` on an empty line |
+| Unordered lists | `- item` or `* item` |
+| Ordered lists | `1. item` |
+| Inline code | `` `code` `` |
+| Links | `[label](url)` |
+| Images | `![alt text](image_url)` |
+| Blockquotes | `> quoted text` |
+| Headings | `#`, `##`, `###` |
+
+:: Basic Markdown syntax {#tbl:markdown-syntax-basic}
+
+## Preview
+
+The preview tab updates in real time as you type. For example, if your variable file contains:
+
+```yaml
+novel:
+ title: "Diary of {{novel.author}}"
+ author: "Anne Frank"
+```
+
+Then typing:
+
+```
+The novel *{{novel.title}}* is a widely read book.
+```
+
+Will render as:
+
+> The novel *Diary of Anne Frank* is a widely read book.
+
+To autocomplete variable names:
+
+1. Create a new file.
+1. Type in a partial variable value, such as `Dia`.
+1. Press [Ctrl+Space]{.kbd} (hold down the [Control]{.kbd} key and tap [Space]{.kbd}).
+
+The editor inserts:
+
+```
+{{novel.title}}
+```
+
+And the preview tab shows:
+
+> Diary of Anne Frank
+
+## Export
+
+To export your document as a PDF:
+
+1. Click **File → Export As → PDF**.
+1. Select a theme from the drop-down list.
+1. Click **OK** or press [⏎ Enter]{.kbd}.
+1. Choose a file name and location.
+1. Click **Save**.
+
+The document will be typeset using ConTeXt and saved as a PDF. You can view it in any PDF reader.
+
+To combine multiple documents into one PDF:
+
+1. Click **File → Export As → Joined PDF**.
+1. Or press [Ctrl+Shift+p]{.kbd}.
+
docs/04-variables.md
+# Variables
+
+Variables are placeholders for values that can be defined once and reused
+throughout the document. When the document is built, each variable is replaced
+with its corresponding value.
+
+## YAML file format
+
+YAML (meaning, *YAML Ain't Markup Language*) is a plain-text format used for
+storing structured data. It's commonly used in configuration files due to its
+readability and simplicity. YAML uses indentation to represent hierarchy and
+supports key-value pairs.
+
+Any number of variables can be defined, in any order:
+
+``` yaml
+key_1: Value 1
+key_2: Value 2
+```
+
+A variable's value can reference other variables by enclosing the referenced
+key in double curly braces (`{{ }}`), wrapped in quotation marks:
+
+``` yaml
+key: Value
+key_1: "{{key}} 1"
+key_2: "{{key}} 2"
+```
+
+Variables can be nested to group related information:
+
+``` yaml
+document:
+ title: Document Title
+ author: Author Name
+ isbn: 978-3-16-148410-0
+```
+
+Reference nested keys using a period, such as:
+
+``` yaml
+novel:
+ author: Author Name
+copyright:
+ owner: "{{novel.author}}"
+```
+
+## Usage
+
+The preview tab updates as you type. Imagine a variable file contains:
+
+``` yaml
+novel:
+ title: "Diary of {{novel.author}}"
+ author: "Anne Frank"
+```
+
+Then typing:
+
+```
+The novel *{{novel.title}}* is a widely read book.
+```
+
+Displays in the preview pane as:
+
+> The novel *Diary of Anne Frank* is a widely read book.
+
+## Autocomplete
+
+Typing variable names is laborious. To autocomplete variable names:
+
+1. Type in a partial variable value, such as `Dia`.
+1. Press [Ctrl+Space]{.kbd} (hold down the [Control]{.kbd} key and tap [Space]{.kbd}).
+
+The editor inserts:
+
+```
+{{novel.title}}
+```
+
+And the preview tab shows:
+
+> Diary of Anne Frank
+
docs/05-metadata.md
+# Metadata
+
+Metadata is information about a document and often includes a title, author
+keywords, copyright date, ISBN, word counts, and more. Most systems require
+coupling metadata directly to the source document. {{app.title}} fetches
+variable definitions from variable definitions file instead. This allows
+reusing the same metadata across documents.
+
+Metadata can be injected into a document either through the document properties
+settings in the user interface or by passing in `--metadata` arguments when
+run from the command line.
+
+## Document properties
+
+Metadata can be mapped in the user preferences, shown in [@fig:gui-metadata].
+When the document is exported, the document metadata variables are added to the
+`<head>` tag as `<meta>` tags.
+
+![Metadata screenshot](images/screenshots/09.png)
+
+:: Custom metadata {#fig:gui-metadata}
+
+The **Key** column lists metadata names and the **Value** column lists the
+metadata content for each corresponding **Key**. The content may include
+references to variable definitions. When the document is typeset, the values
+for the variables will be substituted upon export. When exporting to XHTML
+format, the header will include the keys and values as `<meta>` tags. For
+example:
+
+``` html
+<head>
+ <title>Document Title</title>
+ <meta content="science, nature" name="keywords"/>
+ <meta content="Penn Surnom" name="author"/>
+ <meta content="4311" name="count"/>
+</head>
+```
+
+## Command-line
+
+Recall the document metadata from earlier:
+
+``` yaml
+document:
+ title: Document Title
+ author: Author Name
+```
+
+These data can be provided via command-line arguments as follows:
+
+``` bash
+keenwrite.bin \
+ -i "01-introduction.md" \
+ -v "metadata.yaml" \
+ --metadata="title={{document.title}}" \
+ --metadata="author={{document.author}}"
+```
+
+The resulting XHTML document will resemble:
+
+``` html
+<head>
+ <title>Document Title</title>
+ <meta content="Author Name" name="author"/>
+ <meta content="1234" name="count"/>
+</head>
+```
+
+We'll take a deeper look at command-line usages later.
+
+## Special fields
+
+Certain metadata keys have special handling and formatting rules when documents
+are exported to different formats. When exporting the document, note the
+following special metadata:
+
+* **count** -- Document word count, always included.
+* **author** -- Included as PDF metadata.
+* **keywords** -- Included as PDF metadata.
+* **document.title** -- Populates the `<title>` tag, not a `<meta>` tag.
+
+Except for **count**, all of these metadata variables can be customized.
+
+Some themes, such as *Handrit*, have additional metadata that may be included
+in the final document automatically. *Handrit*, in particular, has a way to
+pass in a pseudonym (or by-line) for publishing manuscripts under a pen name.
+
docs/06-basic-formatting.md
+# Basic formatting
+
+This section outlines the basic formatting elements supported by {{app.title}},
+including paragraphs, headers, lists, links, and tables. There are countless
+resources available on Markdown syntax, so only the most basic review is given
+here.
+
+## Paragraphs
+
+Paragraphs are created by separating blocks of text with one or more blank
+lines.
+
+``` markdown
+This is the first paragraph.
+
+This is the second paragraph.
+```
+
+## Headers
+
+Headers are created using one or more hash (`#`) symbols followed by a space
+and the header text. The number of hash symbols indicates the level of the
+header.
+
+``` markdown
+# Header level 1
+## Header level 2
+### Header level 3
+```
+
+In technical documents, try to limit subheading levels to maintain clarity;
+usually, three levels are sufficient.
+
+## Lists
+
+Ordered lists use numbers followed by a period and a space. Unordered lists
+use asterisks (`*`), plus signs (`+`), or hyphens (`-`) followed by a space.
+
+### Ordered list
+
+My preference is to use `1.` for each ordered item and let the computer
+renumber them because it makes adding and removing items faster.
+
+``` markdown
+1. First item
+1. Second item
+1. Third item
+```
+
+### Unordered list
+
+My preference is to use `*` for the first level of unordered items.
+
+``` markdown
+* Item one
+* Item two
+* Item three
+```
+
+## Links
+
+Links are created using square brackets for the link text followed by
+parentheses for the URL.
+
+``` markdown
+[Download](https://keenwrite.com)
+```
+
+## Tables
+
+Tables use pipes (`|`) to separate columns and hyphens (`-`) to define the
+header row.
+
+``` markdown
+| Column A | Column B | Column C |
+|----------|----------|----------|
+| Value 1 | Value 2 | Value 3 |
+| Value 4 | Value 5 | Value 6 |
+```
+
+Alignment can be suggested using a colon (`:`) on the left, right, or both sides
+(centering) of the header separator line.
+
+``` markdown
+| Column A | Column B | Column C |
+|:-----------|:---------:|----------:|
+| Value 1 | Value 2 | Value 3 |
+| Value 4 | Value 5 | Value 6 |
+```
+
docs/07-advanced-formatting.md
+# Advanced formatting
+
+This chapter covers advanced formatting features that enhance document structure and presentation. These features help create professional documents with rich content organization, proper cross-referencing, and typographic excellence.
+
+## Fenced divs
+
+Fenced divs provide a way to create structured XHTML `div` elements within Markdown documents. They offer semantic organization and styling capabilities beyond basic Markdown formatting.
+
+### Basic syntax
+
+A fenced div uses the following basic syntax:
+
+``` markdown
+::: name
+Content
+:::
+```
+
+To create a fenced div, begin a line with at least three colons (`:::`), followed by at least one space, followed by any word. Content follows immediately on the next line. Terminate the fence with at least three colons.
+
+The XHTML generated from the fence above will resemble:
+
+``` html
+<div class="name">
+<p>Content</p>
+</div>
+```
+
+### Extended syntax
+
+Fenced divs support extended syntax for more control. The syntax can provide a unique identifier, multiple class names, and key/value data pairs:
+
+``` markdown
+::: {#poem-01 .stanza author="Emily Dickinson" year=1890}
+Because I could not stop for Death --
+He kindly stopped for me --
+The Carriage held but just Ourselves --
+And Immortality.
+:::
+```
+
+This produces:
+
+``` html
+<div id="poem-01" class="stanza" data-author="Emily Dickinson" data-year="1890">
+<p>Because I could not stop for Death –
+He kindly stopped for me –
+The Carriage held but just Ourselves –
+And Immortality.</p>
+</div>
+```
+
+When using this syntax, prefix class styles with a period (e.g., `.stanza`).
+
+### Nested syntax
+
+Fenced blocks may be nested to create complex document structures:
+
+``` markdown
+::: poem
+:::::: stanza
+Because I could not stop for Death --
+He kindly stopped for me --
+The Carriage held but just Ourselves --
+And Immortality.
+::::::
+:::
+```
+
+This produces nested `div` elements:
+
+``` html
+<div class="poem"><div class="stanza">
+<p>Because I could not stop for Death –
+He kindly stopped for me –
+The Carriage held but just Ourselves –
+And Immortality.</p>
+</div></div>
+```
+
+## Code blocks
+
+In technical documentation, including source code snippets can help illustrate
+concepts. The syntax for such snippets is exemplified in the following
+quintessential BASIC program:
+
+ ``` basic
+ 10 print "hi"
+ 20 goto 10
+ ```
+
+The word `basic` provides a hint to the presentation layer to colourise the
+syntax according to the rules of the BASIC programming language. Code blocks
+are also used to draw diagrams using text-based syntaxes. See
+[@sec:text-diagrams] for details.
+
+## Captions and cross-references
+
+Captions provide context and descriptions for tables, figures, equations, and other document elements. Cross-references allow linking to these captioned items throughout the document.
+
+### Caption syntax
+
+Captions start with a double colon (`::`) separated by a blank line from the item they describe. The blank line is essential for proper formatting.
+
+For images:
+
+``` markdown
+![image title](https://example.com/image.png)
+
+:: Figure caption text
+```
+
+For tables:
+
+``` markdown
+| a | b | c |
+|---|---|---|
+| 1 | 2 | 3 |
+| 4 | 5 | 6 |
+
+:: Table caption text
+```
+
+For equations:
+
+``` markdown
+$$E = mc^2$$
+
+:: Equation caption text
+```
+
+### Cross-references
+
+Cross-references use anchor names and reference tags to link to captioned
+items. The syntax is:
+
+- `{#type-name:label}` for defining an anchor name
+- `[@type-name:label]` for referencing the anchor elsewhere
+
+Example with image and cross-reference:
+
+``` markdown
+In [@fig:animal], a cute animal is shown.
+
+![image title](https://example.com/cat.png)
+
+:: World's cutest animal {#fig:animal}
+
+There is no cuter animal than the one in [@fig:animal].
+```
+
+Anchors can include a wide variety of type names and labels, such as:
+
+``` markdown
+{#fig:cats}
+{#图版:猫}
+{#eq:mass-energy}
+{#eqn:laplace}
+```
+
+### Predefined type names
+
+To simplify writing captions and references, predefined type names correspond
+to labels commonly used in documents. These labels automatically generate
+suitable names. [@tbl:type-names] lists predefined cross-reference type names
+along with their associated labels, which are inserted automatically into the
+document.
+
+| Type name | English name |
+|----------------------------------|--------------|
+| algorithm, alg | Algorithm |
+| equation, eqn, eq | Equation |
+| figure, fig | Figure |
+| formula | Formula |
+| listing, list, lst, source, src | Listing |
+| lyric | Lyrics |
+| music, score | Score |
+| table, tbl, tab | Table |
+
+:: Predefined cross-reference types and labels {#tbl:type-names}
+
+## Quotation marks
+
+Understanding quotation mark encoding helps ensure proper typography in both digital and print formats. Different encoding options provide flexibility for various output requirements.
+
+[@tbl:quote-encoding] lists available encoding choices.
+
+| Option | Encoding | Description |
+|----------|------------|---------------------------------------------|
+| regular | | Do not encode |
+| apos | `&apos;` | Curled when typeset to PDF |
+| aposhex | `&#x27;` | Apostrophe's numeric value |
+| quote | `&rsquo;` | Right single quotation mark |
+| quotehex | `&#8217;` | Right single quotation mark's numeric value |
+| modifier | `&#x2bc;` | The modifier letter apostrophe |
+
+:: Single straight quote encoding options {#tbl:quote-encoding}
+
+When typesetting to PDF, only the semantically correct `&apos;` value will be
+curled automatically.
+
+### History
+
+The origins of quotation marks trace back to scholarly annotation practices in
+Ancient Greece. Greek scribes used marginal symbols like the diplé (`⟩`) to
+highlight notable passages. A variant, the diplé periestigmene (`⸖`)—a diplé
+accompanied by dots—was used by scholars to indicate disagreement with earlier
+interpretations. These marks laid groundwork for distinguishing quoted text.
+
+By the seventeenth century, quotation marks appeared regularly in printed
+texts. Western European typographers in the nineteenth century adopted the
+convention of turning quotation mark pairs outward, creating the familiar
+"double curved" style.
+
+Early mechanical typewriters lacked many punctuation marks. Straight single and
+double quotes served multiple roles: quotation marks, apostrophes, feet and
+inches, and mathematical primes. Computer character sets later codified
+straight quotes, creating ongoing typographical challenges.
+
+Modern standards recommend using the right single quotation mark (`’`) for
+apostrophes, though this creates semantic ambiguity since the same character
+closes dialogue. Consider the sentence:
+
+> Ambiguity lurks in \"\'cause the horses\'\".
+
+The meaning of `'cause` (*because* vs. *induce*) determines whether to use an
+opening quote or apostrophe, highlighting how historical decisions still impact
+modern typography.
+
+## Mathematics
+
+Mathematical expressions can be embedded using TeX notation, to typeset
+formulas and equations.
+
+### Inline mathematics
+
+For inline mathematical expressions, enclose TeX code in single dollar signs:
+
+``` tex
+The equation $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$ is the quadratic formula.
+```
+
+### Display mathematics
+
+For standalone equations, use double dollar signs:
+
+``` tex
+$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
+```
+
+### Common TeX notation
+
+Basic mathematical elements use standard TeX syntax:
+
+- Fractions: `\frac{numerator}{denominator}`
+- Square roots: `\sqrt{expression}`
+- Superscripts: `x^2`
+- Subscripts: `x_1`
+- Greek letters: `\alpha`, `\beta`, `\gamma`, etc.
+- Integrals: `\int`
+- Summations: `\sum`
+- Limits: `\lim_{x \to 0}`
+
+More complex expressions combine these elements:
+
+``` tex
+$$\sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6}$$
+
+$$\lim_{x \to 0} \frac{\sin x}{x} = 1$$
+```
+
+When exported to XHTML, mathematical expressions can be output as TeX
+notation for use with KaTeX or MathJax. Or as SVG images. When exported to PDF,
+the typesetting system renders expressions directly.
+
docs/08-images.md
+# Images
+
+This chapter covers how to insert and manage document images. You can embed
+standard images, create text-based diagrams, and---as we'll see
+later---integrate plots from R. The application supports various image formats
+and provides flexible path resolution for both local and remote images.
+
+## Inserting images
+
+Insert an image into your Markdown document using the following syntax:
+
+``` markdown
+![image description](path)
+```
+
+Replace `image description` with a descriptive caption for the image and `path`
+with either a local file path or URL where the image is located.
+
+For example, to embed a local image file named `chart.png` located in the same
+directory as your document, you could write:
+
+``` markdown
+![Sales Chart](chart.png)
+```
+
+To embed an image from a remote server, use its URL:
+
+``` markdown
+![Company Logo](https://keenwrite.com/images/logo/title.svg)
+```
+
+The application will automatically display the image in the preview tab once it
+is successfully resolved.
+
+## Image server
+
+By default, all text diagrams are sent to [Kroki](https://kroki.io) for
+conversion into SVG images. A network connection is required to render
+all text diagrams. There is a configuration option to change servers and
+Kroki is open source, so it is possible to keep all source diagrams
+on premises by setting up a locally hosted image server.
+
+## Text diagrams
+
+{{app.title}} distinguishes between diagrams and source code listings by
+prefixing diagrams with a `diagram-` prefix, such as:
+
+ ``` diagram-plantuml
+ @startuml
+ Alice -> Bob: Hello
+ @enduml
+ ```
+
+This has a few benefits. First, it allows rendering diagram types using a
+service without having to codify all possible diagram types. Second, when a new
+type of diagram is added, it's available immediately without needing to upgrade
+the text editor. Third, it clearly distinguishes between a code block to be
+rendered visually and one to be listed as verbatim source code.
+
+Typically, source code is presented in code blocks that include the language
+name so that syntax highlighting can be applied:
+
+ ``` c
+ main() {
+ printf( "hello, world" );
+ }
+ ```
+
+### Mermaid
+
+GitHub created a *de facto* standard that prevents parsers from dynamically
+distinguishing between a diagram to render and source code to list. The
+following code block could be either a source code listing or a pie chart:
+
+ ``` mermaid
+ pie
+ title Turkish Empire Proportions, 1789
+ "Asia" : 66
+ "Africa" : 20
+ "Europe" : 14
+ ```
+
+While tagging the block as `mermaid-lang` could help, it creates a special case
+that needs to be programmed into Markdown parsers. (Having both `c-lang` and
+`c` is redundant.) The `diagram-` prefix side-steps the issue while keeping
+true to the human-readability nature of Markdown. For this reason, using
+`mermaid` alone for a fenced code block will show the source code rather than
+draw a diagram.
+
+## Image paths
+
+Image file discovery enables flexible and intelligent handling of image links
+within documents. It supports both remote and local image sources, and attempts
+to resolve incomplete or relative paths.
+
+### Resolution strategy
+
+The algorithm follows a multi-step process to determine the correct image file
+to display:
+
+1. **Remote URLs** -- If the image reference begins with a remote protocol
+(e.g., `http://`, `https://`), it is accepted as valid and used directly.
+1. **Fully qualified paths** -- If the image refers to a specific file
+path on the local system and the file is readable, it is used as-is.
+1. **Relative paths** -- For unqualified links, the system checks if the image
+exists relative to the base directory of the current document. If not found,
+and there's no extension, all common image file name extensions (e.g., `.svg`,
+`.png`, `.jpg`) are tried.
+
+If the image cannot be resolved through any of the above methods, an error is
+logged to indicate the missing file.
+
+### Resolution example
+
+A document that includes `![Logo](company-logo)` is resolved as follows:
+
+1. If `company-logo` is a remote URL, try to fetch it.
+1. Look for a local file named `company-logo`.
+1. Look for a file named `company-logo` in a specified images directory.
+1. Look for `company-logo.png`, `company-logo.jpg`, etc.
+1. Use the first valid readable matching file found, or log an error.
+
docs/09-exporting.md
+# Exporting documents
+
+{{app.title}} can convert Markdown documents to XHTML, PDF, and plain text
+formats. The application has conveniences for concatenating multiple files
+together prior to typesetting.
+
+## Collating
+
+When exporting multiple documents, the application uses an alphanumeric sorting
+algorithm to determine the order files are concatenated prior to processing.
+This files are collated in a natural order that honours both alphabetic and
+numeric sequences within file names.
+
+Consider the following file names:
+
+```
+chapter_1.md
+chapter_2a.md
+chapter_3.md
+chapter_10.md
+```
+
+Without alphanumeric sorting, `chapter_10.md` would incorrectly appear before
+`chapter_2a.md` in a standard alphabetic sort.
+
+## Batch Processing
+
+The application can process a single document or multiple documents. Batch
+processing automatically discovers and processes additional files based on the
+actively edited file's location and extension.
+
+### Single document export
+
+Export a single document as follows:
+
+1. Open the document to export.
+1. Click **File → Export As → PDF** (or type [Ctrl+p]{.kbd}).
+1. Select a theme from the drop-down list.
+1. Set the output file name.
+1. Click **Save**.
+
+The document is exported.
+
+### Multi-document export
+
+Export multiple documents into a single, concatenated file:
+
+1. Open any document in the directory containing files to export.
+1. Click **File → Export As → Joined PDF** (or type [Ctrl+Shift+p]{.kbd}).
+1. Select a theme from the drop-down list.
+1. Set the output file name.
+1. Click **Save**.
+
+The application searches recursively through the directory hierarchy starting
+from the actively edited file's location. All files with the same extension are
+discovered, sorted using the alphanumeric algorithm, and concatenated prior
+to exporting.
+
+If the first file processed contains numeric digits in its name, only files
+containing numeric digits will be included in the export. If the first file
+contains no digits, all matching files are processed in alphabetical order.
+
+### Chapter ranges
+
+Chapter ranges can be restrict exporting to specific chapters. The range
+specification supports several formats:
+
+* Individual chapters: `1,3,5` exports only chapters 1, 3, and 5.
+* Range: `1-5` exports chapters 1 through 5, inclusive.
+* Starting range: `-5` exports chapters 1 through 5.
+* Open-ended range: `3-` exports chapter 3 and all subsequent chapters.
+* Multiple ranges: `1,3-7,10-` exports chapter 1, chapters 3 through 7, and chapter 10 onwards.
+
+## XHTML exports
+
+When exporting to XHTML format, the application produces standards-compliant
+XHTML documents that can be viewed in web browsers or further processed.
+
+XHTML export features include:
+
+* Document metadata is added to the `<head>` tag as `<meta>` tags
+* Diagrams and visualizations are embedded as `<image>` elements
+* Cross-references and internal links are preserved
+* Mathematical expressions can be output in multiple formats
+
+Mathematical expressions in XHTML exports can be rendered as:
+
+* TeX notation for processing by KaTeX or MathJax; or
+* SVG images for direct display without requiring additional libraries.
+
+## PDF exports
+
+PDF exports use the ConTeXt typesetting system to produce high-quality output.
+Mathematical expressions are rendered directly by TeX-based software, ensuring
+optimal typography for technical content.
+
+Before exporting to PDF format, be sure to have installed the theme pack and
+ConTeXt. See [@cha:installation] for details.
+
+## Theme selection
+
+Themes control the visual appearance of exported PDF documents, including
+fonts, spacing, colours, and layout. The application includes several predefined
+themes, each optimized for different document types and purposes.
+
+Some themes include:
+
+* **Boschet** -- Based on Baskerville font with elegant styling.
+* **Handrit** -- Based on Courier font in double-spaced manuscript format.
+* **Tarmes** -- Based on Times Roman font with minimal styling.
+* **TeXomus** -- A technical format suitable for user manuals.
+
+Theme selection is available during PDF export through the theme drop-down menu
+in the export dialog. Each theme may have specific font requirements that must
+be installed separately.
+
+Create themes by copying and modifying existing ones, such as *TeXomus* or
+*Tarmes*.
+
docs/10-themes.md
+# Themes
+
+Themes in {{app.title}} define the visual appearance and layout of typeset PDF
+documents. They control elements fonts, spacing, colours, page dimensions, and
+structural formatting. Users can achieve high-quality outputs without modifying
+document content. Themes are based on ConTeXt setups and can be selected during
+PDF export to match different document purposes, such as manuscripts, user
+manuals, or wills.
+
+## Customization
+
+Users may define unique document appearances by creating new theme setups. This
+involves structuring a theme directory with required files to integrate with
+the application's typesetting process.
+
+All themes must have:
+
+* a separate directory;
+* a main entry point;
+* a reference to XHTML setups; and
+* a properties file.
+
+For example, a new theme named "dīvus" would have the following file structure,
+relative to the themes directory:
+
+```
+dīvus/
+├── main.tex
+├── xhtml.tex
+└── theme.properties
+```
+
+### Theme directory
+
+The theme directory organizes all files for a single theme. For consistency,
+the theme directory name:
+
+* must not include spaces;
+* must a sibling directory of all other themes;
+* should be lowercase; and
+* should be a single word (Latin works well).
+
+### Entry point
+
+The theme's main entry point defines how the document is presented during
+typesetting. The main entry point, `main.tex`, is passed to the typesetting
+software by the editor immediately prior to typesetting. The purpose of the
+entry point is to import all the other files that define how the document is to
+be presented.
+
+Minimally, the file must include the XHTML setups file, which may be
+accomplished with the following line:
+
+``` tex
+\input xhtml
+```
+
+### XHTML setups
+
+XHTML setups map document elements to typesetting commands. To typeset the
+document, the editor first converts the content into a data format known as
+XHTML. Using XHTML allows mapping common document elements to commands that the
+typesetting software can execute to format the output document.
+
+A file named `xhtml.tex` must exist alongside the main file (that is, in the
+same directory). The file must contain the following:
+
+``` tex
+\usesubpath[../xhtml]
+\input ../xhtml/setups
+```
+
+These commands instruct the typesetter to import instructions from the `xhtml`
+directory, which must exist in the parent directory. The XHTML setups are
+responsible for translating XML elements from the XHTML document into ConTeXt
+macros.
+
+### Properties file
+
+The `theme.properties` files identify a theme's name to the application. This
+file allows the editor to display a drop-down having user-friendly names. The
+format of the file follows:
+
+``` properties
+name=Theme Name
+```
+
+The `name` is the key that the editor uses and the `Theme Name` is the value
+that the theme's author may assign. For the dīvus example, the file would
+resemble:
+
+ name=Dīvus
+
+For consistency, the theme name:
+
+* should use title case (start words with an uppercase letter);
+* should be short (will be truncated to 20 characters);
+* must be uniquely named; and
+* must not contain punctuation (letters and numbers only).
+
+If a theme does not contain this file, the theme will be unavailable for users
+to select when exporting.
+
+## Resources
+
+Styling themes with ConTeXt macros is beyond this manual's scope. Refer to the
+theme source code for examples. Additionally, the following links are
+excellent resources for support:
+
+* [ConTeXt Mailing List](https://mailman.ntg.nl/mailman/listinfo/ntg-context)
+* [TeX Stack Exchange](https://tex.stackexchange.com/questions/tagged/context)
+
+See [@sec:typesetting-resources] for a library of books on ConTeXt.
+
docs/11-math.md
+# Math
+
+Mathematical expressions are embedded using TeX notation, to typeset formulas
+and equations. TeX is a powerful typesetting system created by Donald Knuth for
+producing high-quality documents, especially those with complex mathematical
+and scientific notation. With TeX, you write plain text files with commands and
+then compile them into a final output, like a PDF.
+
+{{app.title}} recognizes only plain TeX so as to be compatible with both
+ConTeXt and LaTeX typesetting systems.
+
+## TeX notation
+
+All TeX commands start with a backslash (`\\`), followed by the name of the
+command, and often use braces (`{}`) to contain their arguments.
+
+Some simple mathematical elements using standard TeX syntax include:
+
+- Fractions: `\frac{numerator}{denominator}`
+- Square roots: `\sqrt{expression}`
+- Superscripts: `x^2`
+- Subscripts: `x_1`
+- Greek letters: `\alpha`, `\beta`, `\gamma`, etc.
+- Integrals: `\int`
+- Summations: `\sum`
+- Limits: `\lim_{x \to 0}`
+
+More complex expressions combine these elements:
+
+``` tex
+\sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6}
+```
+
+Produces:
+
+
+When exported to XHTML, mathematical expressions can be output as:
+
+* TeX notation for use with KaTeX or MathJax; or
+* as SVG images.
+
+When exported to PDF, the typesetting system renders expressions directly.
+
+## Inline expressions
+
+For inline mathematical statements, enclose TeX code in single dollar signs (`$`):
+
+``` tex
+The equation $x=\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$ is the quadratic formula.
+```
+
+## Standalone expressions
+
+For standalone statements, use double dollar signs (`$$`):
+
+``` tex
+$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
+```
+
docs/12-r.md
+# R
+
+This chapter describes how to use R within the application to add dynamic
+content to documents. It covers integration basics, environment setup, creating
+visualizations, working with external data, and using YAML variables in R code.
+
+## Integration
+
+R integration allows embedding R code directly into documents for dynamic
+content generation, such as statistical analysis and data plots. The
+application supports R Markdown (`.Rmd`) files, where R code can be executed
+inline or in chunks to produce results, including numerical outputs and
+visualizations. KeenWrite's R integration is largely compatible with the
+syntax for pandoc / knitr.
+
+## Environment
+
+Setting up the R environment involves configuring scripts and directories to
+load custom functions and manage file locations. This ensures R code runs
+smoothly within the application.
+
+### Bootstrapping
+
+A bootstrap script loads custom R libraries or functions at startup. Complete
+the following steps to call an R function from your own library:
+
+1. Click **File → New** to create a new file.
+1. Click **File → Save As**.
+1. Browse to your home directory.
+1. Set **Name** to: `library.R`.
+1. Click **Save**.
+1. Set the contents to:
+
+ ``` r
+ sum <- function( a, b ) {
+ a + b
+ }
+ ```
+
+1. Click the **Save** icon.
+1. Click **R → Script**.
+1. Set the **R Startup Script** contents to:
+
+ ``` r
+ source( 'library.R' );
+ ```
+
+1. Click **OK**.
+1. Create a new file.
+1. Set the contents to:
+
+ ``` r
+ `r#sum( 5, 5 )`
+ ```
+
+1. Save the file as `sum.R`.
+
+The preview tab shows the result of calling the `sum` function:
+
+> 10.0
+
+This shows how the bootstrap script can load `library.R`, which defines a `sum`
+function that is called by name in the Markdown document.
+
+### Working Directory
+
+The working directory determines where R searches for source files. Accomplish
+this as follows:
+
+1. Click **R → Directory**.
+1. Set **Directory** to a different directory.
+1. Click **OK**.
+1. Create the directory if it does not exist.
+1. Move `library.R` into the directory.
+1. Append a new function to `library.R` as follows:
+
+ ``` r
+ mul <- function( a, b ) {
+ a * b
+ }
+ ```
+
+1. Click **R → Script**.
+1. Set the **R Startup Script** contents to:
+
+ ``` r
+ setwd( v$application$r$working$directory );
+ source( "library.R" );
+ ```
+
+1. Change `sum.Rmd` to:
+
+ ``` r
+ `r#mul( 5, 5 )`
+ ```
+
+1. Close the file `sum.Rmd`.
+1. Confirm saving the file when prompted.
+1. Re-open `sum.Rmd`.
+
+The preview tab shows:
+
+> 25.0
+
+Calling `setwd` using `v$application$r$working$directory` changes the working
+directory where the R engine searches for source files.
+
+## Creating Data Visualizations
+
+Data visualizations enrich documents by incorporating statistical analysis and
+plots generated from R code. The application supports R integration for
+creating these elements within R Markdown files.
+
+Follow these steps to run basic R code within the application:
+
+1. Start the application.
+1. Click **File → New** to create a new file.
+1. Click **File → Save As**.
+1. Set **Name** to: `addition.Rmd`
+1. Click **Save**.
+
+Setting the file name extension tells the application what processor to use
+when transforming the contents for display in the preview tab. Continue by
+typing in the following text, including the backticks:
+
+``` r
+`r#1 + 1`
+```
+
+The preview tab shows the result of `1` plus `1`:
+
+> 2.0
+
+## Working with External Data
+
+Working with external data involves sourcing R files from specified directories
+to incorporate additional functions or data into documents. This allows
+flexible management of R resources outside the main document.
+
+R files may be sourced from any directory, not just the user's home directory.
+
+## Variable definitions
+
+Variables provide a way to define reusable values that can be referenced
+dynamically within R code. This section demonstrates how to use externally
+defined variables that can be referenced by R code.
+
+To see how variable definitions work in R, try the following:
+
+1. Create a new file.
+1. Change the contents to (use spaces not tabs):
+
+ ``` yaml
+ project:
+ title: Project Title
+ author: Author Name
+ ```
+
+1. Save the file as `definitions.yaml`.
+1. Click **File → Open**.
+1. Set **Source Files** to **Variable Files**.
+1. Select `definitions.yaml`.
+1. Click **Open**.
+1. Open `sum.Rmd` if it is not already open.
+1. Type: `je`
+1. Press [Ctrl+Space]{.kbd}.
+
+The editor inserts the following text (matches `je` against Pro**je**ct):
+
+``` r
+`r#x( v$project$title )`
+```
+
+The preview tab shows:
+
+> Project Title
+
+This is because the application inserts variable reference names based on the type of file being edited. By default, the R engine does not have a function named `x` defined.
+
+Continue as follows:
+
+1. Click **R → Script**.
+1. Append the following:
+
+ ``` r
+ x <- function( s ) {
+ tryCatch( {
+ r = eval( parse( text = s ) )
+
+ ifelse( is.atomic( r ), r, s );
+ },
+ warning = function( w ) { s },
+ error = function( e ) { s } )
+ }
+ ```
+
+1. Click **OK**.
+1. Close and re-open `sum.Rmd`.
+
+The preview tab shows:
+
+> 25.0
+>
+> Project Title
+
+The `x` function attempts to evaluate the expression defined by the variable.
+This means that the variables can also include expressions that R is capable of
+evaluating.
+
+## Comma-separated values
+
+{{app.title}} ships with many R functions, including one to convert
+comma-separated values into a Markdown table. Consider the following travel
+fares saved as `fares.csv` in the same directory as the main document:
+
+``` csv
+Distance, "Fare ($)"
+26.7, 73.75
+16.4, 56.00
+32.7, 83.25
+77.0, 190.50
+```
+
+Call `csv2md` using a path relative to the R working directory, such as:
+
+``` r
+`r# csv2md( '../docs/fares.csv' );`
+
+:: Taxi fares vs. distance
+```
+
+Convert the document from R Markdown to Markdown from the command line:
+
+``` bash
+keenwrite.bin \
+ --r-script="${HOME}/writing/R/bootstrap.R" \
+ --r-dir="${HOME}/writing/R" \
+ -i 00.Rmd \
+ -o 00.md
+```
+
+The output file, `00.md`, contains the result from running the function:
+
+``` markdown
+|Distance| Fare ($)|
+|:---|---:|
+|26.7| 73.75|
+|16.4| 56.00|
+|32.7| 83.25|
+|77|190.50|
+|Totals|481.65|
+
+:: Taxi fares vs. distance
+```
+
+By isolating the data to an external file, it is possible to replenish
+the file and rebuild the document to insert the latest values.
+
docs/13-gui.md
+# Graphical user interface
+
+This chapter covers customizing the graphical user interface (GUI).
+
+## Skins
+
+A skin defines the visual style of the application. Skins, which are similar to
+cascading style sheet classes, configure the user interface colours, fonts,
+spacing, highlights, drop-shadows, gradients, and so forth. See the [W3C CSS
+tutorial](https://www.w3.org/Style/Examples/011/firstcss) for details.
+
+### Order
+
+The order that stylesheets are applied dictates how styles get overriden. The
+application loads and applies stylesheets in the following order:
+
+1. **scene.css** -- Defines toolbar styling.
+1. **markdown.css** -- Defines text editor styling.
+1. **skins/skin_name.css** -- Main application chrome, extensible.
+1. **custom.css** -- User-defined preferences.
+
+### Customization
+
+This section walks through creating and applying a custom skin step-by-step, to
+personalize the application's appearance. Create a custom skin as follows:
+
+1. Start the application.
+1. Click **File → New** to create a new file.
+1. Click **File → Save As** to rename the file.
+1. Save the file as `custom.css`.
+1. Change the content to the following:
+
+ ``` css
+ .root {
+ -fx-base: rgb( 30, 30, 30 );
+ -fx-background: -fx-base;
+ }
+ ```
+
+Apply the skin as follows:
+
+1. Click **Edit → Preferences** to open the preferences dialog.
+1. Click **Skins** to view the available options.
+1. Click **Browse** to select a custom file.
+1. Browse to and select `custom.css`, created previously.
+1. Click **Open**.
+1. Click **Apply**.
+
+The user interface immediately changes to a dark mode. Continue:
+
+1. Click **OK** to close the dialog.
+1. Change the **rgb** numbers in **custom.css** from `30` to `60`.
+1. Click **File → Save** to save the CSS file.
+
+The user interface immediately changes colour.
+
+### Classes
+
+For more control, this section explains how to use pre-existing skin templates with defined classes, making it easier to tweak the GUI. Accomplish this as follows:
+
+1. Visit the [skin]({{skins.url.main}}) repository directory
+1. Click one of the files (e.g., `haunted_grey.css`).
+1. Click **Raw**.
+1. Copy the entire text.
+1. Return to `custom.css`.
+1. Delete the contents.
+1. Paste the copied text.
+1. Save the file.
+
+To see how the CSS styles are applied to the text editor, open [markdown.css]({{skins.url.markdown}}), which is also in the repository.
+
+### Modena
+
+This section describes the default look used by the application and points to resources for fully customizing the UI beyond basic changes.
+
+The basic look used by the application is _Modena Light_. Typically we only need to override a few classes to completely change the application's look and feel. For a full listing of available styles see the OpenJDK's [Modena CSS file](https://github.com/openjdk/jfx/blob/master/modules/javafx.controls/src/main/resources/com/sun/javafx/scene/control/skin/modena/modena.css).
+
+### JavaFX CSS
+
+JavaFX CSS have advanced styling capabilities. The [Java CSS Reference Guide](https://openjfx.io/javadoc/21/javafx.graphics/javafx/scene/doc-files/cssref.html) shows differences between JavaFX CSS and W3C CSS. The guide covers functions for manipulating colours and gradients using existing colour definitions.
+
+### RichTextFX
+
+The application uses RichTextFX to render the text editor. Styling various text editor classes can require using the prefix `-rtfx` instead of the regular JavaFX `-fx`.
+
+## Fonts
+
+The preview tab uses two categories of fonts: regular and monospace.
+
+### Regular font
+
+To change the regular preview font, complete the following steps:
+
+1. Click **Edit → Preferences**.
+1. Click **Fonts**.
+1. Click **Change** under **Preview Font** for the **Preview pane font name**.
+1. Find the font name by typing or scrolling.
+1. Click the desired font family.
+1. Click **OK**.
+1. Click **Apply**.
+
+The regular preview font is changed.
+
+### Monospace font
+
+To change the monospace preview font, complete the following steps:
+
+1. Click **Edit → Preferences**.
+1. Click **Fonts**.
+1. Click **Change** under **Preview Font** for the **Monospace font name**.
+1. Find the font name by typing or scrolling.
+1. Click the desired font family.
+1. Click **OK**.
+1. Click **Apply**.
+
+The monospace font is changed.
+
+## Internationalization
+
+Internationalization (I18N) support is essential for editing and previewing
+text in multiple languages. Both fonts and language must be set for
+non-Latin-based text. [@tbl:editor-font-families] lists example
+Chinese-Japanese-Korean (CJK) font settings for the editor and preview tabs.
+
+| Tab | Font Family | Language |
+| ------- | ----------------- | ------------------ |
+| Editor | Noto Sans CJK KR | Korean |
+| Editor | Noto Sans CJK JP | Japanese |
+| Editor | Noto Sans CJK HN | Chinese |
+| Editor | Noto Sans CJK SC | Simplified Chinese |
+| Preview | Noto Serif CJK KR | Korean |
+| Preview | Noto Serif CJK JP | Japanese |
+| Preview | Noto Serif CJK HN | Chinese |
+| Preview | Noto Serif CJK SC | Simplified Chinese |
+
+:: Editor and preview tab font families {#tbl:editor-font-families}
+
+### Editor font
+
+Follow these steps to change the editor font:
+
+1. Click **Edit → Preferences**.
+1. Click **Fonts**.
+1. Click **Change** under **Editor Font**.
+1. Find the font name by typing or scrolling.
+1. Click the desired font family.
+1. Click **OK**.
+1. Click **Apply**.
+
+The text editor font is changed.
+
+Note the following:
+
+* Install the desired fonts (restart the application).
+* Enter font name directly if it cannot be selected.
+
+### Language Settings
+
+Language settings control the locale used by the application, which is important when using CJK fonts or other locale-specific features.
+
+Change the locale as follows:
+
+1. Click **Edit → Preferences**.
+1. Click **Language**.
+1. Select a value for **Locale**.
+1. Click **Apply**.
+
+The language is set.
+
docs/14-cli.md
+# Command-line interface
+
+This chapter covers how to use the application from the command line to convert
+Markdown files to various output formats. Without specifying any command-line
+arguments, the application will launch a graphical user interface.
+
+## Common arguments
+
+The most frequently used command-line arguments include:
+
+* `-h` -- displays all command-line arguments, then exits.
+* `-i` -- sets the input file name, must be a full path.
+* `-o` -- sets the output file name, can be a relative path.
+* `-s` -- sets a variable name and value at build time (dynamic data).
+
+Setting a variable name on the command line useful, for example, to pass in a
+product guide version number.
+
+## Example usage
+
+The following invocations will convert `01.md` into the respective file
+formats, determined by the file name extension. In the first case, it will
+become an XHTML page. In the second case, it will become a plain text document
+with all variables interpolated and replaced.
+
+``` bash
+keenwrite.bin \
+ -i "${HOME}/document/01.md" \
+ -o document.xhtml
+
+keenwrite.bin \
+ -i "${HOME}/document/01.md" \
+ -o document.txt \
+ -v "${HOME}/document/variables.yaml"
+```
+
+The following invocation will convert `01.Rmd` to a PDF file and replace
+the metadata using values from the variable definitions file.
+
+``` bash
+keenwrite.bin \
+ -i "${HOME}/document/01.Rmd" \
+ -o document.pdf \
+ --image-dir="${HOME}/document/images" \
+ -v "${HOME}/document/variables.yaml" \
+ --metadata="title={{book.title}}" \
+ --metadata="author={{book.author}}" \
+ --r-dir="${HOME}/document/r" \
+ --r-script="${HOME}/document/r/bootstrap.R" \
+ --theme-dir="${HOME}/document/themes/boschet"
+```
+
+Directory or file names containing spaces must be quoted. For example, on
+Windows:
+
+``` bash
+keenwrite.bin -i "C:\Users\My Documents\01.Rmd" -o document.pdf
+```
+
docs/15-troubleshooting.md
+# Troubleshooting
+
+This chapter addresses common issues that may arise while using {{app.title}}.
+When problems occur, the status bar displays a brief summary of a problem.
+Detailed information is available through the log viewer.
+
+## Log
+
+The application maintains a list of error messages to help diagnose issues.
+
+Click **View → Log** (or press [F12]{.kbd}) to open the log view.
+
+The log window shows various types of information:
+
+* Error messages that indicate specific problems
+* Warning messages about potential issues
+* Information about file operations and processing
+* System events and application state changes
+
+When reporting issues or seeking help, the log information can provide valuable
+context about what the application was doing when problems occurred.
+
+## SVG compatibility
+
+Vector graphics files created in certain applications may encounter
+compatibility issues when embedded in documents. These problems typically
+manifest as rendering failures, missing content, or incorrectly displayed
+graphics.
+
+When referencing a vector graphic using Markdown, the status bar may show the
+following error:
+
+> The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: flowRoot).
+
+This error occurs due to a version mismatch of the `flowRoot` element that
+Inkscape creates. Resolve the issue by changing the SVG version number as
+follows:
+
+1. Edit the vector graphics file using any text editor.
+1. Find `version="1.1"`.
+1. Change the version to: `version="1.2"`.
+1. Save the file.
+
+The SVG will now appear inside the application; however, the text may appear as black blocks.
+
+## Black blocks
+
+Depending on how text is added to a vector graphic in Inkscape, the text may be
+inserted within an element called a `flowRoot`. Although `flowRoot` is
+recognized, the contents may not be fully interpreted, resulting in black
+blocks being drawn instead of text.
+
+![Black text](images/blocked-text)
+
+:: Blocked text {#fig:blocked-text}
+
+Resolve the issue by "unflowing" all text elements as follows:
+
+1. Start Inkscape.
+1. Load the SVG file.
+1. Select all the text elements.
+1. Click **Text → Unflow**.
+
+The text may change size and position; recreate the text without dragging using
+the text tool. After all the text areas have been recreated, continue as
+follows:
+
+1. Click **Edit → XML Editor**.
+1. Expand the **XML Editor** to see more elements.
+1. Delete all elements named `svg:flowRoot`.
+1. Save the file.
+
+When the illustration is reloaded, the black blocks will have disappeared, but
+the text elements may ignore any assigned colour.
+
+## Black text
+
+When an SVG `style` attribute contains a reference to `-inkscape-font-specification`, all values that follow said reference are ignored. This results in black text, shown in [@fig:blacked-text].
+
+![Black text](images/black-text)
+
+:: Missing text {#fig:blacked-text}
+
+Resolve the issue of colourless text as follows:
+
+1. Open the SVG file in a plain text editor.
+1. Remove all references `-inkscape-font-specification:'<FONT>';`, including the trailing (or leading) semicolon.
+1. Save the file.
+
+[@fig:resolved-text] shows colours having reappeared after reloading.
+
+![Resolved text](images/resolved-text)
+
+:: Resolved text {#fig:resolved-text}
+
docs/16-oss.md
+# Open source software
+
+{{app.title}} is free, open source software.
+
+## License
+
+Copyright &copy; 2025 White Magic Software, Ltd.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+The full text of the GPLv2 license can be found at:
+[https://www.gnu.org/licenses/old-licenses/gpl-2.0.html](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
+
+## Architecture overview
+
+[@fig:architecture] illustrates the software's high-level application
+architecture. The architecture involves a processing pipeline that transforms
+Markdown content through multiple stages to produce the final output. The
+Markdown processor contains both prepackaged and custom extensions. This
+extensible architecture allows for specialized processing of various Markdown
+syntaxes.
+
+* The **"Today"** section shows a single flow where a user writes in Markdown,
+which is then processed and converted into a final HTML output. This is
+typical of most conversion programs written today: they can only handle a
+single type of input and a single type of output.
+
+* The **"Proposed"** section shows that the architecture can be updated to
+handle a wider range of input formats, all feeding into a more flexible
+*Processor Chain*. The two-way arrow indicates that the output from one
+processing pass can be be fed back into the next process.
+
+* The **"Example Processing Combination"** section provides a detailed look at
+how the system could handle multiple, complex inputs and outputs
+simultaneously. It shows how different data formats (XML, YAML, JSON, etc.)
+are processed through dedicated processors (XSLT Processor, R Processor,
+etc.) to produce a variety of outputs (R Markdown, Markdown, HTML5),
+demonstrating a more robust and interconnected system.
+
+![architecture](images/architecture/architecture)
+
+:: Software architecture {#fig:architecture}
+
docs/17-appendix.md
+# Appendices
+
+## Screenshots
+
+This section provides application screenshots.
+
+### Variables
+
+Diagrams that include variables are shown in [@fig:screenshot-diagram-graphviz]
+and [@fig:screenshot-diagram-genealogy].
+
+![GraphViz diagram screenshot](images/screenshots/01.png)
+
+:: GraphViz diagram {#fig:screenshot-diagram-graphviz}
+
+![Family tree diagram screenshot](images/screenshots/05.png)
+
+:: Family tree diagram {#fig:screenshot-diagram-genealogy}
+
+### PDF themes
+
+The background of [@fig:screenshot-pdf-themes] depicts a novel being edited.
+
+![PDF themes](images/screenshots/08.png)
+
+:: PDF Themes {#fig:screenshot-pdf-themes}
+
+Highlighted items of note:
+
+* PDF icon in the upper-left
+* Novel metadata as integrated variables towards the top-left
+* Theme selection dialog in the upper-middle
+* Three different styles, including:
+ * Boschet, based on Baskerville font, nicely styled
+ * Handrit, based on Courier font, double-spaced, manuscript format
+ * Tarmes, based on Times Roman font, minimal styling
+* Variations in page numbers
+* Manuscript includes word count, automatically
+* Preferences dialog in the middle
+
+### Internationalization
+
+[@fig:screenshot-locale] shows a poem with locale settings:
+
+![Korean poem screenshot](images/screenshots/02.png)
+
+:: Locale settings {#fig:screenshot-locale}
+
+### Equations
+
+[@fig:screenshot-tex] shows TeX equations in a detached preview tab:
+
+![TeX equations screenshot](images/screenshots/03.png)
+
+:: TeX equations {#fig:screenshot-tex}
+
+### Dockable tabs
+
+[@fig:screenshot-outline] shows a document outline opened and docked in
+bottom-left corner:
+
+![Document outline](images/screenshots/04.png)
+
+:: Document outline {#fig:screenshot-outline}
+
+## Acknowledgments
+
+Contributors and inspirations behind the application include:
+
+* Tomas Mikula: [RichTextFX](https://github.com/TomasMikula/RichTextFX), [WellBehavedFX](https://github.com/TomasMikula/WellBehavedFX), [Flowless](https://github.com/TomasMikula/Flowless), and [UndoFX](https://github.com/TomasMikula/UndoFX)
+* Jens Deters: [FontAwesomeFX](https://bitbucket.org/Jerady/fontawesomefx)
+* Dieter Holz: [PreferencesFX](https://github.com/dlsc-software-consulting-gmbh/PreferencesFX)
+* David Croft: [File Preferences](http://www.davidc.net/programming/java/java-preferences-using-file-backing-store)
+* Alex Bertram: [Renjin](https://www.renjin.org/)
+* Vladimir Schneider: [flexmark](https://github.com/vsch/flexmark-java)
+* Alberto Fernández, Shy Shalom, Kohei Taketa: [juniversalchardet](https://github.com/takscape/juniversalchardet)
+* Morten Nobel-Jørgensen: [Java Image Scaling](https://github.com/mortennobel/java-image-scaling)
+
+Original concept:
+
+* Karl Tauber: [Markdown Writer FX](https://github.com/JFormDesigner/markdown-writer-fx)
+
+Typesetting system:
+
+* Hans Hagen: [ConTeXt](https://www.pragma-ade.com/)
+
+## Typesetting resources
+
+Documents that introduce the typesetting system:
+
+* [What is ConTeXt?](https://www.pragma-ade.com/general/manuals/what-is-context.pdf)
+* [A not so short introduction to ConTeXt](https://github.com/contextgarden/not-so-short-introduction-to-context)
+* [Dealing with XML in ConTeXt MKIV](https://pragma-ade.com/general/manuals/xml-mkiv.pdf)
+* [Typographic Programming](https://www.pragma-ade.com/general/manuals/style.pdf)
+
+The [documentation library](https://wiki.contextgarden.net/Documentation) includes the following gems:
+
+* [ConTeXt Manual](https://www.pragma-ade.nl/general/manuals/ma-cb-en.pdf)
+* [ConTeXt command reference](https://www.pragma-ade.nl/general/qrcs/setup-en.pdf)
+* [METAFUN Manual](https://www.pragma-ade.nl/general/manuals/metafun-p.pdf)
+* [It's in the Details](https://www.pragma-ade.nl/general/manuals/details.pdf)
+* [Fonts out of ConTeXt](https://www.pragma-ade.com/general/manuals/fonts-mkiv.pdf)
+
+Expert-level documentation includes the [LuaTeX Reference Manual](https://www.pragma-ade.nl/general/manuals/luatex.pdf).
+
docs/user-manual.pdf
Binary files differ
src/main/java/com/keenwrite/ExportFormat.java
package com.keenwrite;
-import com.keenwrite.events.StatusEvent;
import com.keenwrite.io.MediaType;
import com.keenwrite.io.MediaTypeExtension;
src/main/java/com/keenwrite/editors/markdown/LinkVisitor.java
}
- protected NodeVisitor createVisitor() {
+ private NodeVisitor createVisitor() {
return new NodeVisitor(
new VisitHandler<>( Link.class, LinkVisitor.this::visit ) );
src/main/java/com/keenwrite/processors/markdown/extensions/spans/BracketedSpanParser.java
* SPDX-License-Identifier: MIT
*/
+/* Copyright 2025 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/* Copyright 2025 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
package com.keenwrite.processors.markdown.extensions.spans;
);
- public BracketedSpanParser( final @NotNull LightInlineParser ignoredParser ) {
+ public BracketedSpanParser( @NotNull final LightInlineParser ignoredParser ) {
}
@Override
- public boolean parse( final @NotNull LightInlineParser parser ) {
+ public boolean parse( @NotNull final LightInlineParser parser ) {
var result = false;
final var input = parser.getInput();
final var index = parser.getIndex();
if( input.charAt( index ) == '[' ) {
- final var closingBracket = input.indexOf( ']', index );
- final var braceStart = input.indexOf( '{', closingBracket );
- final var braceEnd = input.indexOf( '}', braceStart );
+ final var closingBracket = input.indexOf( ']', index + 1 );
+ final var braceStart = input.indexOf( '{', closingBracket + 1 );
- if( closingBracket != -1 && braceStart != -1 && braceEnd != -1 ) {
- final var content = input.subSequence( index + 1, closingBracket );
- final var span = getBracketedSpan(
- input, braceStart, braceEnd, content
- );
+ if( closingBracket != -1 && braceStart != -1 && braceStart == closingBracket + 1 &&
+ (braceStart + 1 >= input.length() || input.charAt( braceStart + 1 ) != '{') ) {
+ final var braceEnd = input.indexOf( '}', braceStart + 1 );
- span.setChars( input.subSequence( index, braceEnd + 1 ) );
- parser.flushTextNode();
- parser.getBlock().appendChild( span );
- parser.setIndex( braceEnd + 1 );
+ if( braceEnd != -1 ) {
+ final var content = input.subSequence( index + 1, closingBracket );
+ final var span = getBracketedSpan(
+ input, braceStart, braceEnd, content
+ );
- result = true;
+ span.setChars( input.subSequence( index, braceEnd + 1 ) );
+ parser.flushTextNode();
+ parser.getBlock().appendChild( span );
+ parser.setIndex( braceEnd + 1 );
+
+ result = true;
+ }
}
}
return result;
}
- private static @NotNull BracketedSpanNode getBracketedSpan(
+ @NotNull
+ private static BracketedSpanNode getBracketedSpan(
final BasedSequence input,
final int braceStart,
@Override
- public void finalizeDocument( final @NotNull InlineParser parser ) {
+ public void finalizeDocument( @NotNull final InlineParser parser ) {
}
@Override
- public void finalizeBlock( final @NotNull InlineParser parser ) {
+ public void finalizeBlock( @NotNull final InlineParser parser ) {
}
}
-
src/test/java/com/keenwrite/processors/markdown/extensions/links/HyperlinkVariablesTest.java
+/* Copyright 2025 White Magic Software, Ltd. -- All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package com.keenwrite.processors.markdown.extensions.links;
+
+import com.keenwrite.processors.ProcessorContext;
+import com.keenwrite.processors.ProcessorFactory;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import static com.keenwrite.ExportFormat.TEXT_MARKDOWN;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class HyperlinkVariablesTest {
+ final String TEXT = "Text";
+ final String URL = "https://localhost";
+ final String EXPECTED = "<html><head></head><body><p>" +
+ "<a href=\"" + URL + "\">" + TEXT + "</a>" +
+ "</p>\n</body></html>";
+
+ @Test
+ void test_MarkdownProcessing_VariablesInLink_RendersHtmlAnchor() {
+ final Supplier<Map<String, String>> DEFINITIONS = () -> Map.of(
+ "text", TEXT,
+ "url", URL
+ );
+
+ final var context = ProcessorContext.builder()
+ .with( ProcessorContext.Mutator::setSourcePath, Paths.get( "test.md" ) )
+ .with( ProcessorContext.Mutator::setDefinitions, DEFINITIONS )
+ .with( ProcessorContext.Mutator::setExportFormat, TEXT_MARKDOWN )
+ .build();
+
+ final var mp = ProcessorFactory.createProcessors( context );
+ final var actual = mp.apply( "[{{text}}]({{url}})" );
+
+ assertEquals( EXPECTED, actual );
+ }
+}
Delta1993 lines added, 21 lines removed, 1972-line increase