| Author | DaveJarvis <email> |
|---|---|
| Date | 2025-09-03 19:42:27 GMT-0700 |
| Commit | 91741f36c3381fa59cf71dff781e0535ce983fbb |
| Parent | bdd99ed |
| +# 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. | ||
| + | ||
| +# 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 | `` | | ||
| +| 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}. | ||
| + | ||
| +# 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 | ||
| + | ||
| +# 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. | ||
| + | ||
| + | ||
| + | ||
| +:: 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. | ||
| + | ||
| +# 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 | | ||
| +``` | ||
| + | ||
| +# 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 | ||
| + | ||
| + | ||
| +:: 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. | ||
| + | ||
| + | ||
| + | ||
| +:: 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 | `'` | Curled when typeset to PDF | | ||
| +| aposhex | `'` | Apostrophe's numeric value | | ||
| +| quote | `’` | Right single quotation mark | | ||
| +| quotehex | `’` | Right single quotation mark's numeric value | | ||
| +| modifier | `ʼ` | The modifier letter apostrophe | | ||
| + | ||
| +:: Single straight quote encoding options {#tbl:quote-encoding} | ||
| + | ||
| +When typesetting to PDF, only the semantically correct `'` 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. | ||
| + | ||
| +# 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 | ||
| + | ||
| +``` | ||
| + | ||
| +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 | ||
| + | ||
| +``` | ||
| + | ||
| +To embed an image from a remote server, use its URL: | ||
| + | ||
| +``` markdown | ||
| + | ||
| +``` | ||
| + | ||
| +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 `` 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. | ||
| + | ||
| +# 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*. | ||
| + | ||
| +# 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. | ||
| + | ||
| +# 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}$$ | ||
| +``` | ||
| + | ||
| +# 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. | ||
| + | ||
| +# 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. | ||
| + | ||
| +# 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 | ||
| +``` | ||
| + | ||
| +# 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. | ||
| + | ||
| + | ||
| + | ||
| +:: 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]. | ||
| + | ||
| + | ||
| + | ||
| +:: 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 {#fig:resolved-text} | ||
| + | ||
| +# Open source software | ||
| + | ||
| +{{app.title}} is free, open source software. | ||
| + | ||
| +## License | ||
| + | ||
| +Copyright © 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. | ||
| + | ||
| + | ||
| + | ||
| +:: Software architecture {#fig:architecture} | ||
| + | ||
| +# 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 {#fig:screenshot-diagram-graphviz} | ||
| + | ||
| + | ||
| + | ||
| +:: Family tree diagram {#fig:screenshot-diagram-genealogy} | ||
| + | ||
| +### PDF themes | ||
| + | ||
| +The background of [@fig:screenshot-pdf-themes] depicts a novel being edited. | ||
| + | ||
| + | ||
| + | ||
| +:: 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: | ||
| + | ||
| + | ||
| + | ||
| +:: Locale settings {#fig:screenshot-locale} | ||
| + | ||
| +### Equations | ||
| + | ||
| +[@fig:screenshot-tex] shows TeX equations in a detached preview tab: | ||
| + | ||
| + | ||
| + | ||
| +:: TeX equations {#fig:screenshot-tex} | ||
| + | ||
| +### Dockable tabs | ||
| + | ||
| +[@fig:screenshot-outline] shows a document outline opened and docked in | ||
| +bottom-left corner: | ||
| + | ||
| + | ||
| + | ||
| +:: 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). | ||
| + | ||
| package com.keenwrite; | ||
| -import com.keenwrite.events.StatusEvent; | ||
| import com.keenwrite.io.MediaType; | ||
| import com.keenwrite.io.MediaTypeExtension; |
| } | ||
| - protected NodeVisitor createVisitor() { | ||
| + private NodeVisitor createVisitor() { | ||
| return new NodeVisitor( | ||
| new VisitHandler<>( Link.class, LinkVisitor.this::visit ) ); |
| * 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 ) { | ||
| } | ||
| } | ||
| - | ||
| +/* 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 ); | ||
| + } | ||
| +} | ||
| Delta | 1993 lines added, 21 lines removed, 1972-line increase |
|---|