Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
M BUILD.md
1
# Build
1
# Introduction
22
3
This document describes how to build the application.
3
This document describes how to build the application and platform binaries.
44
55
# Requirements
66
77
Download and install the following software packages:
88
99
* [OpenJDK 14](https://openjdk.java.net)
1010
* [Gradle 6.4](https://gradle.org/releases)
1111
12
# Compile
12
# Build
1313
14
Build the application as follows:
14
Build the application überjar as follows:
1515
1616
    gradle clean jar
...
2727
2828
    java -jar build\libs\scrivenvar.jar
29
30
# Installers
31
32
This section describes how to set up the development environment and
33
build native executables for supported operating systems.
34
35
## Setup
36
37
Follow these one-time setup instructions to begin:
38
39
1. Ensure `$HOME/bin` is set in the `PATH` environment variable.
40
1. Move `build-template` into `$HOME/bin`.
41
42
Setup is complete.
43
44
## Binaries
45
46
Run the `installer` script to build platform-specific binaries, such as:
47
48
    ./installer -V -o linux
49
50
The `installer` script:
51
52
* downloads a JDK;
53
* generates a run script;
54
* bundles the JDK, run script, and JAR file; and
55
* creates a standalone binary, so no installation required.
56
57
Run `./installer -h` to see all command-line options.
58
59
# Versioning
60
61
Version numbers are read directly from Git using a plugin. The version
62
number is written to `app.properties`, a properties file in the `resources`
63
directory that can be read from within the application.
2964
3065
D CREDITS.md
1
# Credits
2
3
* Dave Jarvis: [Scrivenvar](https://github.com/DaveJarvis/scrivenvar/)
4
* Karl Tauber: [Markdown Writer FX](https://github.com/JFormDesigner/markdown-writer-fx)
5
* Tomas Mikula: [RichTextFX](https://github.com/TomasMikula/RichTextFX), [ReactFX](https://github.com/TomasMikula/ReactFX), [WellBehavedFX](https://github.com/TomasMikula/WellBehavedFX), [Flowless](https://github.com/TomasMikula/Flowless), and [UndoFX](https://github.com/TomasMikula/UndoFX)
6
* Mikael Grev: [MigLayout](http://www.miglayout.com/)
7
* Tom Eugelink: [MigPane](https://github.com/mikaelgrev/miglayout/blob/master/javafx/src/main/java/org/tbee/javafx/scene/layout/fxml/MigPane.java)
8
* Jens Deters: [FontAwesomeFX](https://bitbucket.org/Jerady/fontawesomefx)
9
* Dieter Holz, [PreferencesFX](https://github.com/dlsc-software-consulting-gmbh/PreferencesFX)
10
* David Croft, [File Preferences](http://www.davidc.net/programming/java/java-preferences-using-file-backing-store)
11
* Alex Bertram, [Renjin](https://www.renjin.org/)
12
* Vladimir Schneider: [flexmark](https://github.com/vsch/flexmark-java)
13
* Michael Kay, [XSLT Processor](http://www.saxonica.com/)
14
* Shy Shalom, Kohei Taketa: [juniversalchardet](https://github.com/takscape/juniversalchardet)
15
161
M README.md
4545
## Usage
4646
47
See the following documents for more information:
48
49
* [USAGE.md](USAGE.md) -- Variable definitions and string interpolation
50
* [USAGE-R.md](USAGE-R.md) -- Call R functions within R Markdown documents
51
* [USAGE-SVG.md](USAGE-SVG.md) -- Fix known issues with displaying SVG files
47
See the [detailed documentation](docs/README.md) for information about
48
using the application.
5249
5350
## Future Features
D USAGE-R.md
1
# Introduction
2
3
This document describes how to use the [R](https://www.r-project.org/)
4
programming language from within the application. The application uses an
5
interpreter known as [Renjin](https://www.renjin.org/) to integrate with R.
6
7
# Hello world
8
9
Complete the following steps to see R in action:
10
11
1. Start the application.
12
1. Click **File → New** to create a new file.
13
1. Click **File → Save As**.
14
1. Set **Name** to: `addition.Rmd`
15
1. Click **Save**.
16
17
Setting the file name extension tells the application what processor to
18
use when transforming the contents for display in the preview pane. Continue
19
by typing in the following text, including the backticks:
20
21
```r
22
`r#1 + 1`
23
```
24
25
The preview pane shows the result of `1` plus `1`:
26
27
```
28
2.0
29
```
30
31
# Bootstrap script
32
33
Being able to run R code while editing an R Markdown document is convenient.
34
Having the ability to call functions is where the power of R can be
35
leveraged.
36
37
Complete the following steps to call an R function from your own library:
38
39
1. Click **File → New** to create a new file.
40
1. Click **File → Save As**.
41
1. Browse to your home directory.
42
1. Set **Name** to: `library.R`.
43
1. Click **Save**.
44
1. Set the contents to:
45
    ``` r
46
    sum <- function( a, b ) {
47
      a + b
48
    }
49
    ```
50
1. Click the **Save** icon.
51
1. Click **R → Script**.
52
1. Set the **R Startup Script** contents to:
53
    ``` r
54
    source( 'library.R' );
55
    ```
56
1. Click **OK**.
57
1. Create a new file.
58
1. Set the contents to:
59
    ``` r
60
    `r#sum( 5, 5 )`
61
    ```
62
1. Save the file as `sum.R`.
63
64
The preview panel shows the result of calling the `sum` function:
65
66
```
67
10.0
68
```
69
70
This shows how the bootstrap script can load `library.R`, which defines
71
a `sum` function that is called by name in the Markdown document.
72
73
# Working directory
74
75
R files may be sourced from any directory, not just the user's home
76
directory. Accomplish this as follows:
77
78
1. Click **R → Directory**.
79
1. Set **Directory** to a different directory.
80
1. Click **OK**.
81
1. Create the directory if it does not exist.
82
1. Move `library.R` into the directory.
83
1. Append a new function to `library.R` as follows:
84
    ``` r
85
    mul <- function( a, b ) {
86
      a * b
87
    }
88
    ```
89
1. Click **R → Script**.
90
1. Set the **R Startup Script** contents to:
91
    ``` r
92
    setwd( '$application.r.working.directory$' );
93
    source( 'library.R' );
94
    ```
95
1. Change `sum.Rmd` to:
96
    ``` r
97
    `r#mul( 5, 5 )`
98
    ```
99
1. Close the file `sum.Rmd`.
100
1. Confirm saving the file when prompted.
101
1. Re-open `sum.Rmd`.
102
103
The preview panel shows:
104
105
```
106
25.0
107
```
108
109
Calling `setwd` using `'$application.r.working.directory$'` changes the
110
working directory where the R engine searches for source files.
111
112
# YAML definitions
113
114
To see how variable definitions work in R, try the following:
115
116
1. Create a new file.
117
1. Change the contents to (use spaces not tabs):
118
    ``` yaml
119
    project:
120
      title: Project Title
121
      author: Author Name
122
    ```
123
1. Save the file as `definitions.yaml`.
124
1. Click **File → Open**.
125
1. Set **Source Files** to **Definition Files**.
126
1. Select `definitions.yaml`.
127
1. Click **Open**.
128
1. Open `sum.Rmd` if it is not already open.
129
1. Type: `je`
130
1. Press `Ctrl+Space`
131
132
The editor inserts the following text (matches `je` against Pro**je**ct):
133
134
``` r
135
`r#x( v$project$title )`
136
```
137
138
The preview panel shows:
139
140
```
141
r#x( 'Project Title' )
142
```
143
144
This is because the application inserts definition reference names based
145
on the type of file being edited. By default, the R engine does not have
146
a function named `x` defined.
147
148
Continue as follows:
149
150
1. Click **R → Script**.
151
1. Append the following:
152
    ``` r
153
    x <- function( s ) {
154
      tryCatch( {
155
        r = eval( parse( text = s ) )
156
157
        ifelse( is.atomic( r ), r, s );
158
      },
159
      warning = function( w ) { s },
160
      error = function( e ) { s } )
161
    }
162
    ```
163
1. Click **OK**.
164
1. Close and re-open `sum.Rmd`.
165
166
The preview panel shows:
167
168
```
169
25.0
170
171
Project Title
172
```
173
174
The `x` function attempts to evaluate the expression defined by the YAML
175
variable. This means that the YAML definitions can also include expressions
176
that R is capable of evaluating.
177
178
While the `x` function can be defined within the R Startup Script, it is
179
better practice to put it into its own library so that it can be reused
180
outside of the application.
181
1821
D USAGE-SVG.md
1
# Introduction
2
3
The Scalable Vector Graphics (SVG) drawing software---[Batik](https://xmlgraphics.apache.org/batik/)---that's used by the application may be unable to read certain SVG files produced by [Inkscape](https://inkscape.org/). The result is that embedding the vector graphics files may trigger the following issues:
4
5
* Unable to create nested element
6
* Black blocks, no text displayed
7
* Black text instead of coloured
8
9
The remainder of this document explains these problems and how to fix them.
10
11
# Nested element
12
13
When referencing a vector graphic using Markdown, the status bar may show the following error:
14
15
> The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: flowRoot).
16
17
This error is due to a version mismatch of the `flowRoot` element that Inkscape creates.
18
19
## Fix
20
21
Resolve the issue by changing the SVG version number as follows:
22
23
1. Edit the vector graphics file using any text editor.
24
1. Find `version="1.1"` and change it to `version="1.2"`.
25
1. Save the file.
26
27
The SVG will now appear inside the application; however, the text may appear as black blocks.
28
29
# Black blocks
30
31
Depending on how text is added to a vector graphic in Inkscape, the text may be inserted within an element called a `flowRoot`. Although Batik recognizes `flowRoot` for SVG version 1.2, it cannot fully interpret the contents. Black blocks are drawn instead of the text, such as those depicted in the following figure:
32
33
![Missing text](images/blocked-text.png)
34
35
## Fix
36
37
Resolve the issue by "unflowing" all text elements as follows:
38
39
1. Start Inkscape.
40
1. Load the SVG file.
41
1. Select all the text elements.
42
1. Click **Text → Unflow**.
43
44
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:
45
46
1. Click **Edit → XML Editor**.
47
1. Expand the **XML Editor** to see more elements.
48
1. Delete all elements named `svg:flowRoot`.
49
1. Save the file.
50
51
When the illustration is reloaded, the black blocks will have disappeared, but the text elements ignore any assigned colour.
52
53
# Black text
54
55
When an SVG `style` attribute contains a reference to `-inkscape-font-specification`, Batik ignores all values that follow said reference. This results in black text, such as:
56
57
![Black text](images/black-text.png)
58
59
## Fix
60
61
Resolve the issue of colourless text as follows:
62
63
1. Open the SVG file in a plain text editor.
64
1. Remove all references `-inkscape-font-specification:'<FONT>';`, including the trailing (or leading) semicolon.
65
1. Save the file.
66
67
When the illustration is reloaded, the colours will have reappeared, such as:
68
69
![Resolved text](images/resolved-text.png)
70
711
D USAGE.md
1
# Introduction
2
3
This document describes how to use the application.
4
5
# Variable definitions
6
7
Variable definitions provide a way to insert key names having associated values into a document. The variable names and values are declared inside an external file using the [YAML](http://www.yaml.org/) file format. Simply put, variables are written in the file as follows:
8
9
```
10
key: value
11
```
12
13
Any number of variables can be defined, in any order:
14
15
```
16
key_1: Value 1
17
key_2: Value 2
18
```
19
20
Variables can reference other variables by enclosing the key name within dollar symbols:
21
22
```
23
key: Value
24
key_1: $key$ 1
25
key_2: $key$ 2
26
```
27
28
Variables can use a nested structure to help group related information:
29
30
```
31
novel:
32
  title: Book Title
33
  author: Author Name
34
  isbn: 978-3-16-148410-0
35
```
36
37
Use a period to reference nested keys, such as:
38
39
```
40
novel:
41
  author: Author Name
42
copyright:
43
  owner: $novel.author$
44
```
45
46
Save the variable definitions in a file having an extension of `.yaml` or `.yml`.
47
48
# Document editing
49
50
The application's purpose is to completely separate the document's content from its presentation. To achieve this, documents are composed using a [plain text](http://spec.commonmark.org/0.28/) format.
51
52
## Create document
53
54
Start a new document as follows:
55
56
1. Start the application.
57
1. Click **File → New** to create an empty document to edit.
58
1. Click **File → Open** to open a variable definition file.
59
1. Change **Source Files** to **Definition Files** to list definition files.
60
1. Browse to and select a file saved with a `.yaml` or `.yml` extension.
61
1. Click **Open**.
62
63
The variable definitions appear in the variable definition pane under the heading of **Definitions**.
64
65
## Edit document
66
67
Edit the document as normal. Notice how the preview pane updates as new content is added. The toolbar shows various icons that perform different formatting operations. Try them to see how they appear in the preview pane. Other operations not shown on the toolbar include:
68
69
* Struck text (enclose the words within `~~` and `~~`)
70
* Horizontal rule (use `---` on an otherwise empty line).
71
72
The preview pane shows one way to interpret and format the document, but many other presentations are possible.
73
74
## Insert variable
75
76
Let's assume that the variable definitions loaded into the application include:
77
78
```
79
novel:
80
  title: Diary of $novel.author$
81
  author: Anne Frank
82
```
83
84
To reference a variable, type in the key name enclosed within dollar symbols, such as:
85
86
```
87
The novel "$novel.title$" is one of the most widely read books in the world.
88
```
89
90
The preview pane shows:
91
92
> The novel "Diary of Anne Frank" is one of the most widely read books in the world.
93
94
As it is laborious to type in variable names, it is possible to inject the variable name using autocomplete. Accomplish this as follows:
95
96
1. Create a new file.
97
1. Type in a partial variable value, such as **Dia**.
98
1. Press `Ctrl+Space` (hold down the `Control` key and tap the spacebar).
99
100
The editor shows:
101
102
```
103
$novel.title$
104
```
105
106
The preview pane shows:
107
108
```
109
Diary of Anne Frank
110
```
111
112
The variable name is inserted into the document and the preview pane shows the variable's value.
113
1141
M build.gradle
173173
}
174174
175
A docs/README.md
1
## Documents
2
3
See the following documents for more information:
4
5
* [definitions.md](definitions.md) -- Definitions and interpolation
6
* [r.md](r.md) -- Call R functions within R Markdown documents
7
* [svg.md](svg.md) -- Fix known issues with displaying SVG files
8
* [credits.md](credits.md) -- Thanks to authors of contributing projects
9
110
A docs/credits.md
1
# Credits
2
3
* Karl Tauber: [Markdown Writer FX](https://github.com/JFormDesigner/markdown-writer-fx)
4
* Tomas Mikula: [RichTextFX](https://github.com/TomasMikula/RichTextFX), [ReactFX](https://github.com/TomasMikula/ReactFX), [WellBehavedFX](https://github.com/TomasMikula/WellBehavedFX), [Flowless](https://github.com/TomasMikula/Flowless), and [UndoFX](https://github.com/TomasMikula/UndoFX)
5
* Mikael Grev: [MigLayout](http://www.miglayout.com/)
6
* Tom Eugelink: [MigPane](https://github.com/mikaelgrev/miglayout/blob/master/javafx/src/main/java/org/tbee/javafx/scene/layout/fxml/MigPane.java)
7
* Jens Deters: [FontAwesomeFX](https://bitbucket.org/Jerady/fontawesomefx)
8
* Dieter Holz, [PreferencesFX](https://github.com/dlsc-software-consulting-gmbh/PreferencesFX)
9
* David Croft, [File Preferences](http://www.davidc.net/programming/java/java-preferences-using-file-backing-store)
10
* Alex Bertram, [Renjin](https://www.renjin.org/)
11
* Vladimir Schneider: [flexmark](https://github.com/vsch/flexmark-java)
12
* Michael Kay, [XSLT Processor](http://www.saxonica.com/)
13
* Shy Shalom, Kohei Taketa: [juniversalchardet](https://github.com/takscape/juniversalchardet)
14
115
A docs/definitions.md
1
# Introduction
2
3
This document describes how to use the application.
4
5
# Variable definitions
6
7
Variable definitions provide a way to insert key names having associated values into a document. The variable names and values are declared inside an external file using the [YAML](http://www.yaml.org/) file format. Simply put, variables are written in the file as follows:
8
9
```
10
key: value
11
```
12
13
Any number of variables can be defined, in any order:
14
15
```
16
key_1: Value 1
17
key_2: Value 2
18
```
19
20
Variables can reference other variables by enclosing the key name within dollar symbols:
21
22
```
23
key: Value
24
key_1: $key$ 1
25
key_2: $key$ 2
26
```
27
28
Variables can use a nested structure to help group related information:
29
30
```
31
novel:
32
  title: Book Title
33
  author: Author Name
34
  isbn: 978-3-16-148410-0
35
```
36
37
Use a period to reference nested keys, such as:
38
39
```
40
novel:
41
  author: Author Name
42
copyright:
43
  owner: $novel.author$
44
```
45
46
Save the variable definitions in a file having an extension of `.yaml` or `.yml`.
47
48
# Document editing
49
50
The application's purpose is to completely separate the document's content from its presentation. To achieve this, documents are composed using a [plain text](http://spec.commonmark.org/0.28/) format.
51
52
## Create document
53
54
Start a new document as follows:
55
56
1. Start the application.
57
1. Click **File → New** to create an empty document to edit.
58
1. Click **File → Open** to open a variable definition file.
59
1. Change **Source Files** to **Definition Files** to list definition files.
60
1. Browse to and select a file saved with a `.yaml` or `.yml` extension.
61
1. Click **Open**.
62
63
The variable definitions appear in the variable definition pane under the heading of **Definitions**.
64
65
## Edit document
66
67
Edit the document as normal. Notice how the preview pane updates as new content is added. The toolbar shows various icons that perform different formatting operations. Try them to see how they appear in the preview pane. Other operations not shown on the toolbar include:
68
69
* Struck text (enclose the words within `~~` and `~~`)
70
* Horizontal rule (use `---` on an otherwise empty line).
71
72
The preview pane shows one way to interpret and format the document, but many other presentations are possible.
73
74
## Insert variable
75
76
Let's assume that the variable definitions loaded into the application include:
77
78
```
79
novel:
80
  title: Diary of $novel.author$
81
  author: Anne Frank
82
```
83
84
To reference a variable, type in the key name enclosed within dollar symbols, such as:
85
86
```
87
The novel "$novel.title$" is one of the most widely read books in the world.
88
```
89
90
The preview pane shows:
91
92
> The novel "Diary of Anne Frank" is one of the most widely read books in the world.
93
94
As it is laborious to type in variable names, it is possible to inject the variable name using autocomplete. Accomplish this as follows:
95
96
1. Create a new file.
97
1. Type in a partial variable value, such as **Dia**.
98
1. Press `Ctrl+Space` (hold down the `Control` key and tap the spacebar).
99
100
The editor shows:
101
102
```
103
$novel.title$
104
```
105
106
The preview pane shows:
107
108
```
109
Diary of Anne Frank
110
```
111
112
The variable name is inserted into the document and the preview pane shows the variable's value.
113
1114
A docs/r.md
1
# Introduction
2
3
This document describes how to use the [R](https://www.r-project.org/)
4
programming language from within the application. The application uses an
5
interpreter known as [Renjin](https://www.renjin.org/) to integrate with R.
6
7
# Hello world
8
9
Complete the following steps to see R in action:
10
11
1. Start the application.
12
1. Click **File → New** to create a new file.
13
1. Click **File → Save As**.
14
1. Set **Name** to: `addition.Rmd`
15
1. Click **Save**.
16
17
Setting the file name extension tells the application what processor to
18
use when transforming the contents for display in the preview pane. Continue
19
by typing in the following text, including the backticks:
20
21
```r
22
`r#1 + 1`
23
```
24
25
The preview pane shows the result of `1` plus `1`:
26
27
```
28
2.0
29
```
30
31
# Bootstrap script
32
33
Being able to run R code while editing an R Markdown document is convenient.
34
Having the ability to call functions is where the power of R can be
35
leveraged.
36
37
Complete the following steps to call an R function from your own library:
38
39
1. Click **File → New** to create a new file.
40
1. Click **File → Save As**.
41
1. Browse to your home directory.
42
1. Set **Name** to: `library.R`.
43
1. Click **Save**.
44
1. Set the contents to:
45
    ``` r
46
    sum <- function( a, b ) {
47
      a + b
48
    }
49
    ```
50
1. Click the **Save** icon.
51
1. Click **R → Script**.
52
1. Set the **R Startup Script** contents to:
53
    ``` r
54
    source( 'library.R' );
55
    ```
56
1. Click **OK**.
57
1. Create a new file.
58
1. Set the contents to:
59
    ``` r
60
    `r#sum( 5, 5 )`
61
    ```
62
1. Save the file as `sum.R`.
63
64
The preview panel shows the result of calling the `sum` function:
65
66
```
67
10.0
68
```
69
70
This shows how the bootstrap script can load `library.R`, which defines
71
a `sum` function that is called by name in the Markdown document.
72
73
# Working directory
74
75
R files may be sourced from any directory, not just the user's home
76
directory. Accomplish this as follows:
77
78
1. Click **R → Directory**.
79
1. Set **Directory** to a different directory.
80
1. Click **OK**.
81
1. Create the directory if it does not exist.
82
1. Move `library.R` into the directory.
83
1. Append a new function to `library.R` as follows:
84
    ``` r
85
    mul <- function( a, b ) {
86
      a * b
87
    }
88
    ```
89
1. Click **R → Script**.
90
1. Set the **R Startup Script** contents to:
91
    ``` r
92
    setwd( '$application.r.working.directory$' );
93
    source( 'library.R' );
94
    ```
95
1. Change `sum.Rmd` to:
96
    ``` r
97
    `r#mul( 5, 5 )`
98
    ```
99
1. Close the file `sum.Rmd`.
100
1. Confirm saving the file when prompted.
101
1. Re-open `sum.Rmd`.
102
103
The preview panel shows:
104
105
```
106
25.0
107
```
108
109
Calling `setwd` using `'$application.r.working.directory$'` changes the
110
working directory where the R engine searches for source files.
111
112
# YAML definitions
113
114
To see how variable definitions work in R, try the following:
115
116
1. Create a new file.
117
1. Change the contents to (use spaces not tabs):
118
    ``` yaml
119
    project:
120
      title: Project Title
121
      author: Author Name
122
    ```
123
1. Save the file as `definitions.yaml`.
124
1. Click **File → Open**.
125
1. Set **Source Files** to **Definition Files**.
126
1. Select `definitions.yaml`.
127
1. Click **Open**.
128
1. Open `sum.Rmd` if it is not already open.
129
1. Type: `je`
130
1. Press `Ctrl+Space`
131
132
The editor inserts the following text (matches `je` against Pro**je**ct):
133
134
``` r
135
`r#x( v$project$title )`
136
```
137
138
The preview panel shows:
139
140
```
141
r#x( 'Project Title' )
142
```
143
144
This is because the application inserts definition reference names based
145
on the type of file being edited. By default, the R engine does not have
146
a function named `x` defined.
147
148
Continue as follows:
149
150
1. Click **R → Script**.
151
1. Append the following:
152
    ``` r
153
    x <- function( s ) {
154
      tryCatch( {
155
        r = eval( parse( text = s ) )
156
157
        ifelse( is.atomic( r ), r, s );
158
      },
159
      warning = function( w ) { s },
160
      error = function( e ) { s } )
161
    }
162
    ```
163
1. Click **OK**.
164
1. Close and re-open `sum.Rmd`.
165
166
The preview panel shows:
167
168
```
169
25.0
170
171
Project Title
172
```
173
174
The `x` function attempts to evaluate the expression defined by the YAML
175
variable. This means that the YAML definitions can also include expressions
176
that R is capable of evaluating.
177
178
While the `x` function can be defined within the R Startup Script, it is
179
better practice to put it into its own library so that it can be reused
180
outside of the application.
181
1182
A docs/svg.md
1
# Introduction
2
3
The Scalable Vector Graphics (SVG) drawing software---[Batik](https://xmlgraphics.apache.org/batik/)---that's used by the application may be unable to read certain SVG files produced by [Inkscape](https://inkscape.org/). The result is that embedding the vector graphics files may trigger the following issues:
4
5
* Unable to create nested element
6
* Black blocks, no text displayed
7
* Black text instead of coloured
8
9
The remainder of this document explains these problems and how to fix them.
10
11
# Nested element
12
13
When referencing a vector graphic using Markdown, the status bar may show the following error:
14
15
> The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: flowRoot).
16
17
This error is due to a version mismatch of the `flowRoot` element that Inkscape creates.
18
19
## Fix
20
21
Resolve the issue by changing the SVG version number as follows:
22
23
1. Edit the vector graphics file using any text editor.
24
1. Find `version="1.1"` and change it to `version="1.2"`.
25
1. Save the file.
26
27
The SVG will now appear inside the application; however, the text may appear as black blocks.
28
29
# Black blocks
30
31
Depending on how text is added to a vector graphic in Inkscape, the text may be inserted within an element called a `flowRoot`. Although Batik recognizes `flowRoot` for SVG version 1.2, it cannot fully interpret the contents. Black blocks are drawn instead of the text, such as those depicted in the following figure:
32
33
![Missing text](images/blocked-text.png)
34
35
## Fix
36
37
Resolve the issue by "unflowing" all text elements as follows:
38
39
1. Start Inkscape.
40
1. Load the SVG file.
41
1. Select all the text elements.
42
1. Click **Text → Unflow**.
43
44
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:
45
46
1. Click **Edit → XML Editor**.
47
1. Expand the **XML Editor** to see more elements.
48
1. Delete all elements named `svg:flowRoot`.
49
1. Save the file.
50
51
When the illustration is reloaded, the black blocks will have disappeared, but the text elements ignore any assigned colour.
52
53
# Black text
54
55
When an SVG `style` attribute contains a reference to `-inkscape-font-specification`, Batik ignores all values that follow said reference. This results in black text, such as:
56
57
![Black text](images/black-text.png)
58
59
## Fix
60
61
Resolve the issue of colourless text as follows:
62
63
1. Open the SVG file in a plain text editor.
64
1. Remove all references `-inkscape-font-specification:'<FONT>';`, including the trailing (or leading) semicolon.
65
1. Save the file.
66
67
When the illustration is reloaded, the colours will have reappeared, such as:
68
69
![Resolved text](images/resolved-text.png)
70
171
A scripts/.gitignore
1
*.class
12
A scripts/01.sikuli/01.py
1
# -----------------------------------------------------------------------------
2
# Copyright 2020 White Magic Software, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish,
8
# distribute, sublicense, and/or sell copies of the Software, and to
9
# permit persons to whom the Software is furnished to do so, subject to
10
# the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
# -----------------------------------------------------------------------------
23
24
# -----------------------------------------------------------------------------
25
# This script introduces the editor and its purpose.
26
# -----------------------------------------------------------------------------
27
import sys
28
29
if not "../editor.sikuli" in sys.path:
30
    sys.path.append( "../editor.sikuli" )
31
32
from editor import *
33
34
# ---------------------------------------------------------------
35
# Fresh start
36
# ---------------------------------------------------------------
37
rm( app_home + "/variables.yaml" )
38
rm( app_home + "/untitled.md" )
39
rm( home + "/.scrivenvar" )
40
41
# ---------------------------------------------------------------
42
# Wait for application to launch
43
# ---------------------------------------------------------------
44
openApp( "java -jar " + app_bin )
45
46
wait("1594187265140.png", 30)
47
# ---------------------------------------------------------------
48
# Introduction
49
# ---------------------------------------------------------------
50
set_typing_speed( 240 )
51
52
header( "What is this application?" )
53
typer( "Well, this application is a text editor that supports interpolated definitions, ")
54
typer( "a few different text formats, real-time preview, spell check ") 
55
typer( "as you tipe" ) 
56
wait( 0.5 )
57
recur( 3, backspace )
58
typer( "ype, and R statements." )
59
paragraph()
60
wait( 1 )
61
62
# ---------------------------------------------------------------
63
# Definition demo
64
# ---------------------------------------------------------------
65
header( "What are definitions?" )
66
typer( "Watch. " )
67
wait( .5 )
68
69
# Focus the definition editor.
70
click_create()
71
recur( 4, tab )
72
73
wait( .5 )
74
rename_definition( "application" )
75
76
insert()
77
rename_definition( "title" )
78
79
insert()
80
rename_definition( "Scrivenvar" )
81
82
# Set focus to the text editor.
83
tab()
84
85
typer( "The left-hand pane contains a nested, folder-like structure of names " )
86
typer( "and values that are called *definitions*. " )
87
wait( .5 )
88
typer( "Such definitions can simplify updating documents. " )
89
wait( 1 )
90
91
edit_find( "this application" )
92
typer( "$application.title$" )
93
94
edit_find_next()
95
typer( "$application.title$" )
96
97
type( Key.END, Key.CTRL )
98
99
typer( "The right-hand pane shows the result after having substituted definition " )
100
typer( "values into the document." )
101
wait( 2 )
102
paragraph()
103
104
header( "What is interpolation?" )
105
typer( "Definition values can reference definition names. " )
106
wait( .5 )
107
typer( "The definition names act as placeholders. Substituting placeholders with " )
108
typer( "their defined value is called *interpolation*. Let's see how it works." )
109
wait( 2 )
1110
A scripts/01.sikuli/1594187265140.png
Binary file
A scripts/02.sikuli/02.py
1
# -----------------------------------------------------------------------------
2
# Copyright 2020 White Magic Software, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish,
8
# distribute, sublicense, and/or sell copies of the Software, and to
9
# permit persons to whom the Software is furnished to do so, subject to
10
# the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
# -----------------------------------------------------------------------------
23
24
# -----------------------------------------------------------------------------
25
# This script demonstrates how to use interpolated strings.
26
# -----------------------------------------------------------------------------
27
import sys
28
29
if not "../editor.sikuli" in sys.path:
30
    sys.path.append( "../editor.sikuli" )
31
32
from editor import *
33
34
# -----------------------------------------------------------------------------
35
# Open sample chapter.
36
# -----------------------------------------------------------------------------
37
file_open()
38
type( Key.UP, Key.ALT )
39
wait( 1 )
40
typer( Key.END )
41
wait( 1 )
42
enter()
43
wait( 0.5 )
44
enter()
45
wait( 1 )
46
47
# -----------------------------------------------------------------------------
48
# Open the corresponding definition file.
49
# -----------------------------------------------------------------------------
50
file_open()
51
recur( 2, down )
52
wait( 1 )
53
enter()
54
wait( 1 )
55
56
# -----------------------------------------------------------------------------
57
# Edit the sample document.
58
# -----------------------------------------------------------------------------
59
set_typing_speed( 80 )
60
61
type( Key.HOME, Key.CTRL )
62
recur( 2, down )
63
64
# Grey
65
recur( 3, skip_right )
66
autoinsert()
67
68
# 34
69
recur( 4, skip_right )
70
autoinsert()
71
72
# Central
73
recur( 10, skip_right )
74
autoinsert()
75
76
# London
77
skip_right()
78
autoinsert()
79
80
# Hatchery
81
skip_right()
82
autoinsert()
83
84
# and Conditioning
85
recur( 2, select_word_right )
86
delete()
87
88
# Centre
89
skip_right()
90
autoinsert()
91
92
set_typing_speed( 220 )
93
94
typer( " Let's interpolate those four definitions instead!" )
95
wait( 4 )
96
recur( 13, type, Key.BACKSPACE, Key.CTRL )
97
recur( 9, backspace )
98
99
set_typing_speed( 60 )
100
101
typer( "name$" )
102
wait( 2 )
103
104
# Collapse all definitions
105
tab()
106
recur( 8, typer, Key.LEFT )
107
108
# Expand to city
109
recur( 4, typer, Key.RIGHT )
110
111
# Jump to name
112
recur( 2, down )
113
recur( 2, typer, Key.RIGHT )
114
115
# Open the text field to show the full value
116
typer( Key.F2 )
117
118
# Traverse the text field
119
home()
120
recur( 16, type, Key.RIGHT, Key.CTRL )
121
esc()
122
123
restore_typing_speed()
124
125
tab()
126
type( Key.HOME, Key.CTRL )
127
edit_find( "Director" )
128
autoinsert()
129
130
edit_find_next()
131
autoinsert()
132
133
edit_find_next()
134
typer( Key.RIGHT )
135
recur( 2, delete )
136
autoinsert()
137
typer( "'s" )
138
139
edit_find( "Hatcheries" )
140
autoinsert()
141
142
# and Conditioning
143
recur( 2, select_word_right )
144
delete()
145
146
edit_find( "Central" )
147
autoinsert()
148
149
skip_right()
150
autoinsert()
151
152
typer( " How about a different city?" )
153
wait( 2 )
154
recur( 5, type, Key.BACKSPACE, Key.CTRL )
155
wait( 1 )
156
tab()
157
typer( Key.F2 )
158
typer( "Seattle" )
159
enter()
160
tab()
161
wait( 2 )
162
163
type( Key.END, Key.CTRL )
164
paragraph()
165
typer( "No?" )
166
paragraph()
167
168
tab()
169
typer( Key.F2 )
170
typer( "London" )
171
enter()
172
173
tab()
174
typer( "Organizing definitions is left to your ")
175
typer( "doub" )
176
wait( .25 )
177
autoinsert()
178
wait( 1 )
179
typer( " Good imagination." )
180
tab()
181
182
# Jump to "char" definition
183
home()
184
185
# Jump to "char.a.primary.name" definition
186
recur( 6, typer, Key.RIGHT )
187
188
# Jump to "char.a.primary.caste" definition
189
down()
190
typer( Key.RIGHT )
191
192
# Jump to root-level "caste" definition
193
recur( 7, down )
194
195
# Reselect "super"
196
recur( 5, typer, Key.RIGHT )
197
wait( 2 )
198
199
# Close the window, no save
200
type( "w", Key.CTRL )
201
wait( 0.5 )
202
tab()
203
wait( 0.5 )
204
typer( Key.SPACE )
205
wait( 1 )
1206
A scripts/03.sikuli/03.py
1
# -----------------------------------------------------------------------------
2
# Copyright 2020 White Magic Software, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish,
8
# distribute, sublicense, and/or sell copies of the Software, and to
9
# permit persons to whom the Software is furnished to do so, subject to
10
# the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
# -----------------------------------------------------------------------------
23
24
# -----------------------------------------------------------------------------
25
# This script introduces images and R.
26
# -----------------------------------------------------------------------------
27
import sys
28
29
if not "../editor.sikuli" in sys.path:
30
    sys.path.append( "../editor.sikuli" )
31
32
from editor import *
33
34
set_typing_speed( 80 )
35
file_open()
36
type( Key.UP, Key.ALT )
37
wait( 0.5 )
38
home()
39
wait( 0.25 )
40
enter()
41
wait( 1 )
42
end()
43
wait( 0.25 )
44
enter()
45
wait( 1 )
46
47
set_typing_speed( 200 )
48
49
paragraph()
50
header( "What text formats are supported?" )
51
52
typer( "Scr" )
53
autoinsert()
54
typer( " supports Markdown, R Markdown, XML, and R XML; however, the software " )
55
typer( "architecture enables it to easily add new formats. The following figure " )
56
typer( "depicts the overall architecture: " )
57
paragraph()
58
typer( "![](../writing/images/architecture)" )
59
paragraph()
60
typer( "Most text editors read a single format and convert it to one other format. " )
61
typer( "With a little more effort, text editors can support many input and output " )
62
typer( "formats. Scr" )
63
autoinsert()
64
typer( " goes one step further by introducing interpolated definitions." )
65
paragraph()
66
typer( "Kitten interlude:" )
67
paragraph()
68
typer( "![](https://i.imgur.com/jboueQH.jpg)" )
69
paragraph()
70
71
header( "What is R?" )
72
typer( "R is a programming language. You might have noticed a few potential grammar " )
73
typer( "problems with direct substitution. Rules for possessive forms, numbers, and " )
74
typer( "other linguistic exceptions can be addressed using R. Let's take a look!" )
175
A scripts/04.sikuli/04.py
1
# -----------------------------------------------------------------------------
2
# Copyright 2020 White Magic Software, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish,
8
# distribute, sublicense, and/or sell copies of the Software, and to
9
# permit persons to whom the Software is furnished to do so, subject to
10
# the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
# -----------------------------------------------------------------------------
23
24
# -----------------------------------------------------------------------------
25
# This script demonstrates using R.
26
# -----------------------------------------------------------------------------
27
import sys
28
29
if not "../editor.sikuli" in sys.path:
30
    sys.path.append( "../editor.sikuli" )
31
32
from editor import *
33
34
# -----------------------------------------------------------------------------
35
# Open the demo text.
36
# -----------------------------------------------------------------------------
37
file_open()
38
type( Key.UP, Key.ALT )
39
wait( 0.5 )
40
end()
41
wait( 0.25 )
42
enter()
43
wait( 0.5 )
44
down()
45
wait( 0.25 )
46
enter()
47
wait( 1 )
48
49
# -----------------------------------------------------------------------------
50
# Demo bootstrapping
51
# -----------------------------------------------------------------------------
52
53
# Jump to the end.
54
type( Key.END, Key.CTRL )
55
paragraph()
56
57
type( "s", Key.CTRL + Key.ALT )
58
wait( 0.25 )
59
60
61
# -----------------------------------------------------------------------------
62
# Demo pluralization
63
# -----------------------------------------------------------------------------
64
65
66
# -----------------------------------------------------------------------------
67
# Demo possessives (it, she, he, Ross)
68
# -----------------------------------------------------------------------------
69
70
71
# -----------------------------------------------------------------------------
72
# Demo conversion, including ordinal numbers
73
# -----------------------------------------------------------------------------
74
75
# -----------------------------------------------------------------------------
76
# Demo Chicago Manual of Style
77
# -----------------------------------------------------------------------------
78
79
80
# -----------------------------------------------------------------------------
81
# Demo CSV file import
82
# -----------------------------------------------------------------------------
83
84
185
A scripts/editor.sikuli/1594187923258.png
Binary file
A scripts/editor.sikuli/editor.py
1
# -----------------------------------------------------------------------------
2
# Copyright 2020 White Magic Software, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish,
8
# distribute, sublicense, and/or sell copies of the Software, and to
9
# permit persons to whom the Software is furnished to do so, subject to
10
# the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
# -----------------------------------------------------------------------------
23
24
# -----------------------------------------------------------------------------
25
# This script contains helper functions used by the other scripts.
26
#
27
# Do not run this script.
28
# -----------------------------------------------------------------------------
29
30
from sikuli import *
31
import sys
32
import os
33
from os.path import expanduser
34
35
home = expanduser( "~" )
36
app_home = home + "/bin"
37
app_bin = app_home + "/scrivenvar.jar"
38
39
wpm_default_speed = 80
40
wpm_typing_speed = wpm_default_speed
41
42
# -----------------------------------------------------------------------------
43
# Try to delete the file pointed to by the path variable. If there is no such
44
# file, this will silently ignore the exception.
45
# -----------------------------------------------------------------------------
46
def rm( path ):
47
    try:
48
        os.remove( path )
49
    except:
50
        print "Ignored"
51
52
# -----------------------------------------------------------------------------
53
# Changes the current typing speed, where speed is given in words per minute.
54
# -----------------------------------------------------------------------------
55
def set_typing_speed( wpm ):
56
    global wpm_typing_speed
57
    wpm_typing_speed = wpm
58
59
def restore_typing_speed():
60
    set_typing_speed( wpm_default_speed )
61
62
# -----------------------------------------------------------------------------
63
# Creates a delay between keystrokes to emulate typing at a particular speed.
64
# -----------------------------------------------------------------------------
65
def random_wait():
66
    from time import sleep
67
    from random import uniform
68
    cpm = wpm_typing_speed * 5.1
69
    cps = cpm / 60.0
70
    ms_per_char = 1000.0 / cps
71
    ms_per_stroke = ms_per_char / 2.0
72
73
    noise = uniform( 0, ms_per_stroke / 2 )
74
    duration = (ms_per_stroke + noise ) / 1000
75
    
76
    sleep( duration )
77
78
# -----------------------------------------------------------------------------
79
# Repeats a function call, f, n times.
80
# -----------------------------------------------------------------------------
81
def recur( n, f, *args ):
82
    for i in range( n ):
83
        f(*args)
84
        random_wait()
85
86
# -----------------------------------------------------------------------------
87
# Emulate a typist who is typing in the given text.
88
# -----------------------------------------------------------------------------
89
def typer( text ):
90
    # ~25 is a reasonably realistic, fast typist.
91
    for c in text:
92
        type( c )
93
        random_wait()
94
95
# -----------------------------------------------------------------------------
96
# Injects a definition.
97
# -----------------------------------------------------------------------------
98
def autoinsert():
99
    type( Key.SPACE, Key.CTRL )
100
    random_wait()
101
102
# -----------------------------------------------------------------------------
103
# Types the TAB key.
104
# -----------------------------------------------------------------------------
105
def tab():
106
    typer( Key.TAB )
107
108
# -----------------------------------------------------------------------------
109
# Types the ENTER key.
110
# -----------------------------------------------------------------------------
111
def enter():
112
    typer( Key.ENTER )
113
114
# -----------------------------------------------------------------------------
115
# Types the ESC key.
116
# -----------------------------------------------------------------------------
117
def esc():
118
    typer( Key.ESC )
119
120
# -----------------------------------------------------------------------------
121
# Types the DOWN arrow key.
122
# -----------------------------------------------------------------------------
123
def down():
124
    typer( Key.DOWN )
125
126
# -----------------------------------------------------------------------------
127
# Types the HOME key.
128
# -----------------------------------------------------------------------------
129
def home():
130
    typer( Key.HOME )
131
132
# -----------------------------------------------------------------------------
133
# Types the END key.
134
# -----------------------------------------------------------------------------
135
def end():
136
    typer( Key.END )
137
138
# -----------------------------------------------------------------------------
139
# Types the BACKSPACE key.
140
# -----------------------------------------------------------------------------
141
def backspace():
142
    typer( Key.BACKSPACE )
143
144
# -----------------------------------------------------------------------------
145
# Types the INSERT key, often to insert a new definition.
146
# -----------------------------------------------------------------------------
147
def insert():
148
    typer( Key.INSERT )
149
150
# -----------------------------------------------------------------------------
151
# Types the DELETE key, often to remove selected text.
152
# -----------------------------------------------------------------------------
153
def delete():
154
    typer( Key.DELETE )
155
156
# -----------------------------------------------------------------------------
157
# Moves the cursor one word to the right.
158
# -----------------------------------------------------------------------------
159
def skip_right():
160
    type( Key.RIGHT, Key.CTRL )
161
    random_wait()
162
163
def select_word_right():
164
    type( Key.RIGHT, Key.CTRL + Key.SHIFT )
165
    random_wait()
166
167
# -----------------------------------------------------------------------------
168
# Types ENTER twice to begin a new paragraph.
169
# -----------------------------------------------------------------------------
170
def paragraph():
171
    recur( 2, enter )
172
    wait( 1.5 )
173
174
# -----------------------------------------------------------------------------
175
# Writes a heading to the document using the given text value as the content.
176
# -----------------------------------------------------------------------------
177
def header( text ):
178
    typer( "# " + text )
179
    paragraph()
180
181
# -----------------------------------------------------------------------------
182
# Clicks the "Create" button to add a new definition.
183
# -----------------------------------------------------------------------------
184
def click_create():
185
    click("1594187923258.png")
186
    wait( .5 )
187
188
# -----------------------------------------------------------------------------
189
# Changes the text for the actively selected definition.
190
# -----------------------------------------------------------------------------
191
def rename_definition( text ):
192
    typer( Key.F2 )
193
    typer( text )
194
    enter()
195
    wait( .5 )
196
197
# -----------------------------------------------------------------------------
198
# Searches for the given text within the document.
199
# -----------------------------------------------------------------------------
200
def edit_find( text ):
201
    type( "f", Key.CTRL )
202
    typer( text )
203
    enter()
204
    wait( .25 )
205
    esc()
206
    wait( .5 )
207
208
# -----------------------------------------------------------------------------
209
# Searches for the next occurrence of the previous search term.
210
# -----------------------------------------------------------------------------
211
def edit_find_next():
212
    typer( Key.F3 )
213
    wait( .5 )
214
215
# -----------------------------------------------------------------------------
216
# Opens a dialog for selecting a file.
217
# -----------------------------------------------------------------------------
218
def file_open():
219
    type( "o", Key.CTRL )
220
    wait( 1 )
1221
M src/main/java/com/scrivenvar/MainWindow.java
11061106
        .build();
11071107
1108
    // Number of header actions (H1 ... H3)
1109
    final int HEADERS = 3;
1110
    final Action[] headers = new Action[ HEADERS ];
1108
    // Number of heading actions (H1 ... H3)
1109
    final int HEADINGS = 3;
1110
    final Action[] headings = new Action[ HEADINGS ];
11111111
1112
    for( int i = 1; i <= HEADERS; i++ ) {
1112
    for( int i = 1; i <= HEADINGS; i++ ) {
11131113
      final String hashes = new String( new char[ i ] ).replace( "\0", "#" );
11141114
      final String markup = String.format( "%n%n%s ", hashes );
1115
      final String text = "Main.menu.insert.header." + i;
1115
      final String text = "Main.menu.insert.heading." + i;
11161116
      final String accelerator = "Shortcut+" + i;
11171117
      final String prompt = text + ".prompt";
11181118
1119
      headers[ i - 1 ] = new ActionBuilder()
1119
      headings[ i - 1 ] = new ActionBuilder()
11201120
          .setText( text )
11211121
          .setAccelerator( accelerator )
...
12011201
        insertImageAction,
12021202
        null,
1203
        headers[ 0 ],
1204
        headers[ 1 ],
1205
        headers[ 2 ],
1203
        headings[ 0 ],
1204
        headings[ 1 ],
1205
        headings[ 2 ],
12061206
        null,
12071207
        insertUnorderedListAction,
...
12431243
        insertImageAction,
12441244
        null,
1245
        headers[ 0 ],
1245
        headings[ 0 ],
12461246
        null,
12471247
        insertUnorderedListAction,
M src/main/java/com/scrivenvar/preview/HTMLPreviewPane.java
161161
   * rendering on some platforms.
162162
   */
163
  private final static String HTML_HEADER = "<!DOCTYPE html>"
163
  private final static String HTML_PREFIX = "<!DOCTYPE html>"
164164
      + "<html>"
165165
      + "<head>"
166166
      + "<link rel='stylesheet' href='" +
167167
      HTMLPreviewPane.class.getResource( STYLESHEET_PREVIEW ) + "'/>"
168168
      + "</head>"
169169
      + "<body>";
170170
171171
  // Provide some extra space at the end for scrolling past the last line.
172
  private final static String HTML_FOOTER =
172
  private final static String HTML_SUFFIX =
173173
      "<p style='height=2em'>&nbsp;</p></body></html>";
174174
...
195195
    setStyle( "-fx-background-color: white;" );
196196
197
    // No need to append the header each time the HTML content is updated.
198
    mHtmlDocument.append( HTML_HEADER );
197
    // No need to append same prefix each time the HTML content is updated.
198
    mHtmlDocument.append( HTML_PREFIX );
199199
    mHtmlPrefixLength = mHtmlDocument.length();
200200
...
340340
341341
  private String decorate( final String html ) {
342
    // Trim the HTML back to the header.
342
    // Trim the HTML back to only the prefix.
343343
    mHtmlDocument.setLength( mHtmlPrefixLength );
344344
345345
    // Write the HTML body element followed by closing tags.
346346
    return mHtmlDocument.append( html )
347
                        .append( HTML_FOOTER )
347
                        .append( HTML_SUFFIX )
348348
                        .toString();
349349
  }
M src/main/resources/com/scrivenvar/messages.properties
4141
Main.menu.insert.link=Link...
4242
Main.menu.insert.image=Image...
43
Main.menu.insert.header.1=Header 1
44
Main.menu.insert.header.1.prompt=header 1
45
Main.menu.insert.header.2=Header 2
46
Main.menu.insert.header.2.prompt=header 2
47
Main.menu.insert.header.3=Header 3
48
Main.menu.insert.header.3.prompt=header 3
43
Main.menu.insert.heading.1=Heading 1
44
Main.menu.insert.heading.1.prompt=heading 1
45
Main.menu.insert.heading.2=Heading 2
46
Main.menu.insert.heading.2.prompt=heading 2
47
Main.menu.insert.heading.3=Heading 3
48
Main.menu.insert.heading.3.prompt=heading 3
4949
Main.menu.insert.unordered_list=Unordered List
5050
Main.menu.insert.ordered_list=Ordered List
M src/main/resources/com/scrivenvar/preview/webview.css
2727
}
2828
29
/* HEADERS ***/
29
/* HEADINGS ***/
3030
h1, h2, h3, h4, h5, h6 {
3131
  font-weight: bold;