Dave Jarvis' Repositories

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

Move sikuli into test directory

AuthorDaveJarvis <email>
Date2021-03-31 22:46:47 GMT-0700
Commitfb0ed952923fd2a681af7a8d2098e0d8c965634c
Parent1a14cfd
sikuli/.gitignore
-*.class
sikuli/demo.sikuli/1594187265140.png
Binary files differ
sikuli/demo.sikuli/1594592396134.png
Binary files differ
sikuli/demo.sikuli/1594593710440.png
Binary files differ
sikuli/demo.sikuli/1594593794335.png
Binary files differ
sikuli/demo.sikuli/1594594984108.png
Binary files differ
sikuli/demo.sikuli/1594689573764.png
Binary files differ
sikuli/demo.sikuli/demo.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# Runs all scripts
-# -----------------------------------------------------------------------------
-
-import s01
-import s02
-import s03
-import s04
sikuli/demo.sikuli/s01.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# This script introduces the editor and its purpose.
-# -----------------------------------------------------------------------------
-from sikuli import *
-import sys
-
-if not "../editor.sikuli" in sys.path:
- sys.path.append( "../editor.sikuli" )
-
-from editor import *
-
-# ---------------------------------------------------------------
-# Fresh start
-# ---------------------------------------------------------------
-rm( app_home + "/variables.yaml" )
-rm( app_home + "/untitled.md" )
-rm( dir_home + "/.scrivenvar" )
-
-# ---------------------------------------------------------------
-# Wait for application to launch
-# ---------------------------------------------------------------
-openApp( "java -jar " + app_bin )
-
-wait("1594187265140.png", 30)
-
-# Breathing room for video recording.
-wait( 4 )
-
-# ---------------------------------------------------------------
-# Introduction
-# ---------------------------------------------------------------
-set_typing_speed( 240 )
-
-heading( "What is this application?" )
-typer( "Well, this application is a text editor that supports interpolated definitions, ")
-typer( "a few different text formats, real-time preview, spell check ")
-typer( "as you tipe" )
-wait( 0.5 )
-recur( 3, backspace )
-typer( "ype, and R statements." )
-paragraph()
-wait( 1 )
-
-# ---------------------------------------------------------------
-# Definition demo
-# ---------------------------------------------------------------
-heading( "What are definitions?" )
-typer( "Watch. " )
-wait( .5 )
-
-# Focus the definition editor.
-click_create()
-recur( 4, tab )
-
-wait( .5 )
-rename_definition( "application" )
-
-insert()
-rename_definition( "title" )
-
-insert()
-rename_definition( "Scrivenvar" )
-
-# Set focus to the text editor.
-tab()
-
-typer( "The left-hand pane contains a nested, folder-like structure of names " )
-typer( "and values that are called *definitions*. " )
-wait( .5 )
-typer( "Such definitions can simplify updating documents. " )
-wait( 1 )
-
-edit_find( "this application" )
-typer( "$application.title$" )
-
-edit_find_next()
-typer( "$application.title$" )
-
-type( Key.END, Key.CTRL )
-
-typer( "The right-hand pane shows the result after having substituted definition " )
-typer( "values into the document." )
-
-paragraph()
-typer( "Now nobody wants to type definition names all the time. Instead, type any " )
-typer( "partial definition value followed by `Ctrl+Space`, such as: scr" )
-wait( 0.5 )
-autoinsert()
-wait( 1 )
-typer( ". *Much* better!" )
-paragraph()
-
-heading( "What is interpolation?" )
-typer( "Definition values can reference definition names. " )
-wait( .5 )
-typer( "The definition names act as placeholders. Substituting placeholders with " )
-typer( "their definition value is called *interpolation*. Let's see how it works." )
-wait( 2 )
sikuli/demo.sikuli/s02.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# This script demonstrates how to use interpolated strings.
-# -----------------------------------------------------------------------------
-from sikuli import *
-import sys
-
-if not "../editor.sikuli" in sys.path:
- sys.path.append( "../editor.sikuli" )
-
-from editor import *
-
-# -----------------------------------------------------------------------------
-# Open sample chapter.
-# -----------------------------------------------------------------------------
-file_open()
-type( Key.UP, Key.ALT )
-wait( 1 )
-typer( Key.END )
-wait( 1 )
-enter()
-wait( 0.5 )
-enter()
-wait( 1 )
-
-# -----------------------------------------------------------------------------
-# Open the corresponding definition file.
-# -----------------------------------------------------------------------------
-file_open()
-recur( 2, down )
-wait( 1 )
-enter()
-wait( 1 )
-
-# -----------------------------------------------------------------------------
-# Edit the sample document.
-# -----------------------------------------------------------------------------
-set_typing_speed( 80 )
-
-type( Key.HOME, Key.CTRL )
-recur( 2, down )
-
-# Grey
-recur( 3, skip_right )
-autoinsert()
-
-# 34
-recur( 4, skip_right )
-autoinsert()
-
-# Central
-recur( 10, skip_right )
-autoinsert()
-
-# London
-skip_right()
-autoinsert()
-
-# Hatchery
-skip_right()
-autoinsert()
-
-# and Conditioning
-recur( 2, select_word_right )
-delete()
-
-# Centre
-skip_right()
-autoinsert()
-
-set_typing_speed( 220 )
-
-typer( " Let's interpolate those four definitions instead!" )
-wait( 4 )
-recur( 13, type, Key.BACKSPACE, Key.CTRL )
-recur( 9, backspace )
-
-set_typing_speed( 60 )
-
-typer( "name$" )
-wait( 2 )
-
-# Collapse all definitions
-tab()
-recur( 8, typer, Key.LEFT )
-
-# Expand to city
-recur( 4, typer, Key.RIGHT )
-
-# Jump to name
-recur( 2, down )
-recur( 2, typer, Key.RIGHT )
-
-# Open the text field to show the full value
-typer( Key.F2 )
-
-# Traverse the text field
-home()
-recur( 16, type, Key.RIGHT, Key.CTRL )
-esc()
-
-restore_typing_speed()
-
-tab()
-type( Key.HOME, Key.CTRL )
-edit_find( "Director" )
-autoinsert()
-
-edit_find_next()
-autoinsert()
-
-edit_find_next()
-typer( Key.RIGHT )
-recur( 2, delete )
-autoinsert()
-typer( "'s" )
-
-edit_find( "Hatcheries" )
-autoinsert()
-
-# and Conditioning
-recur( 2, select_word_right )
-delete()
-
-edit_find( "Central" )
-autoinsert()
-
-skip_right()
-autoinsert()
-
-typer( " How about a different city?" )
-wait( 2 )
-recur( 5, type, Key.BACKSPACE, Key.CTRL )
-wait( 1 )
-tab()
-typer( Key.F2 )
-typer( "Seattle" )
-enter()
-tab()
-wait( 2 )
-
-type( Key.END, Key.CTRL )
-paragraph()
-typer( "No?" )
-paragraph()
-
-tab()
-typer( Key.F2 )
-typer( "London" )
-enter()
-
-tab()
-typer( "Organizing definitions is left to your ")
-typer( "doub" )
-autoinsert()
-typer( " Good imagination." )
-tab()
-
-# Jump to "char" definition
-home()
-
-# Jump to "char.a.primary.name" definition
-recur( 6, typer, Key.RIGHT )
-
-# Jump to "char.a.primary.caste" definition
-down()
-typer( Key.RIGHT )
-
-# Jump to root-level "caste" definition
-recur( 7, down )
-
-# Reselect "super"
-recur( 5, typer, Key.RIGHT )
-wait( 2 )
-
-# Close the window, no save
-type( "w", Key.CTRL )
-wait( 0.5 )
-tab()
-wait( 0.5 )
-typer( Key.SPACE )
-wait( 1 )
sikuli/demo.sikuli/s03.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# This script introduces images and R.
-# -----------------------------------------------------------------------------
-from sikuli import *
-import sys
-
-if not "../editor.sikuli" in sys.path:
- sys.path.append( "../editor.sikuli" )
-
-from editor import *
-
-set_typing_speed( 80 )
-
-file_open()
-type( Key.UP, Key.ALT )
-wait( 0.5 )
-home()
-wait( 0.25 )
-enter()
-wait( 1 )
-end()
-wait( 0.25 )
-enter()
-wait( 1 )
-
-set_typing_speed( 200 )
-
-paragraph()
-heading( "What text formats are supported?" )
-
-typer( "Scr" )
-autoinsert()
-typer( " supports Markdown, R Markdown, XML, and R XML; however, the software " )
-typer( "architecture enables it to easily add new formats. The following figure " )
-typer( "depicts the overall architecture: " )
-paragraph()
-typer( "![](../writing/images/architecture)" )
-paragraph()
-typer( "Many text editors can only open one type of plain text markup format that is " )
-typer( "only output as HTML. With a little more effort, text editors could support " )
-typer( "multiple input and output formats. Scr" )
-autoinsert()
-typer( " does so and goes one step further by introducing interpolated definitions." )
-paragraph()
-typer( "Kitten interlude:" )
-paragraph()
-typer( "![](https://i.imgur.com/jboueQH.jpg)" )
-paragraph()
-
-heading( "What is R?" )
-typer( "R is a programming language. You might have noticed a few potential grammar " )
-typer( "problems with direct substitution. Rules for possessive forms, numbers, and " )
-typer( "other quirks can be tackled using R." )
-
-# -----------------------------------------------------------------------------
-# Demo bootstrapping
-# -----------------------------------------------------------------------------
-
-# Jump to the end
-type( Key.END, Key.CTRL )
-paragraph()
-
-set_typing_speed( 300 )
-heading( "How is R used?" )
-typer( "R must be instructed where to find script files and what ones to load. The " )
-typer( "*working directory* is the full path to those R files; the *startup script* " )
-typer( "defines what R files to load. Both preferences must be changed before prose " )
-typer( "may be processed. Preferences can be opened using either the " )
-typeln( "**Edit > Preferences** menu or by pressing `Ctrl+Alt+s`. Here goes!" )
-wait( 2 )
-
-# -----------------------------------------------------------------------------
-# Select the R script directory
-# -----------------------------------------------------------------------------
-
-# Change the working directory by clicking "Browse"
-type( "s", Key.CTRL + Key.ALT )
-wait("1594592396134.png", 1)
-click("1594592396134.png")
-wait( 0.5 )
-
-# Navigate to and select the "r" directory
-type( Key.UP, Key.ALT )
-wait( 0.5 )
-end()
-wait( 0.5 )
-enter()
-wait( 0.5 )
-end()
-wait( 0.5 )
-type( Key.UP )
-wait( 0.5 )
-recur( 2, tab )
-wait( 0.5 )
-enter()
-wait( 1 )
-
-# -----------------------------------------------------------------------------
-# Set the R startup script instructions
-# -----------------------------------------------------------------------------
-
-wait("1594593710440.png", 5)
-click("1594593710440.png")
-
-set_typing_speed( 440 )
-
-typeln( "setwd( '$application.r.working.directory$' )" )
-typeln( "assign( 'anchor', '$date.anchor$', envir = .GlobalEnv )" )
-typeln( "source( 'pluralize.R' )" )
-typeln( "source( 'possessive.R' )" )
-typeln( "source( 'conversion.R' )" )
-typeln( "source( 'csv.R' )" )
-
-wait("1594593794335.png", 3)
-click("1594593794335.png")
-
-paragraph()
-set_typing_speed( 220 )
-
-typer( "R is now configured. The startup script and other R " )
-typer( "files can be found in the " )
-typer( "[repository](https://github.com/DaveJarvis/scrivenvar/tree/master/R). " )
-wait( 1.5 )
-
-# Wait for the browser to appear.
-wait("1594594984108.png", 5)
-click("1594594984108.png")
-
-wait( 5 )
-click("1594689573764.png")
-
-paragraph()
-typer( "Next, we'll see how definitions and R can work together." )
-wait( 2 )
sikuli/demo.sikuli/s04.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# This script demonstrates using R.
-# -----------------------------------------------------------------------------
-from sikuli import *
-import sys
-
-if not "../editor.sikuli" in sys.path:
- sys.path.append( "../editor.sikuli" )
-
-from editor import *
-
-set_typing_speed( 220 )
-
-# -----------------------------------------------------------------------------
-# Open the demo text.
-# -----------------------------------------------------------------------------
-file_open()
-type( Key.UP, Key.ALT )
-wait( 0.5 )
-end()
-wait( 0.5 )
-enter()
-wait( 0.5 )
-down()
-wait( 0.5 )
-enter()
-wait( 2 )
-
-# -----------------------------------------------------------------------------
-# Re-open the corresponding definition file.
-# -----------------------------------------------------------------------------
-file_open()
-recur( 2, down )
-wait( 1 )
-enter()
-wait( 2 )
-
-# -----------------------------------------------------------------------------
-# Brief introduction to R
-# -----------------------------------------------------------------------------
-type( Key.HOME, Key.CTRL )
-end()
-paragraph()
-
-typer( "## Using R" )
-paragraph()
-typer( "Insert R code into documents as follows: `r# 1+1`. " )
-wait( 1.5 )
-typer( "Notice how the right-hand pane shows the computed result. I'll wait. " )
-wait( 3 )
-typer( "The syntax is: open backtick, r#, *computable expression*, close " )
-typer( "backtick. That expression can be any valid R statement. The status bar " )
-typer( "will provide clues when an R expression cannot be computed by the " )
-typer( "editor. `r# glitch`" )
-wait( 4 )
-recur( 11, backspace )
-typer( "Let's swap 34 storeys for a definition value and replace the number " )
-typer( "according to the Chicago Manual of Style (cms) rules." )
-
-# -----------------------------------------------------------------------------
-# Demo pluralization
-# -----------------------------------------------------------------------------
-set_typing_speed( 80 )
-
-edit_find( "34" )
-autoinsert()
-
-edit_find( "x(" )
-typer( "cms(" )
-
-edit_find( "storeys." )
-typer( "34." )
-autoinsert()
-edit_find( "x(" )
-typer( "pl( 'storey'," )
-wait( 4 )
-
-tab()
-rename_definition( "1" )
-wait( 4 )
-rename_definition( "142" )
-wait( 4 )
-rename_definition( "34" )
-wait( 4 )
-tab()
-
-# -----------------------------------------------------------------------------
-# Demo possessives (it, her, his, Director)
-# -----------------------------------------------------------------------------
-type( Key.HOME, Key.CTRL )
-edit_find( "Director" )
-autoinsert()
-edit_find_next()
-autoinsert()
-edit_find_next()
-autoinsert()
-type( Key.RIGHT )
-recur( 2, delete )
-autoinsert()
-home()
-edit_find( "x(" )
-typer( "pos(" )
-wait( 2 )
-
-tab()
-rename_definition( "Headmistress" )
-wait( 4 )
-rename_definition( "Director" )
-wait( 2 )
-tab()
-
-type( Key.END, Key.CTRL )
-paragraph()
-typer( "Other possessives: `r# pos( 'it' )`, `r# pos( 'her' )`, `r# pos( 'his' )`, " )
-typer( "and `r# pos( 'my' )`." )
-
-# -----------------------------------------------------------------------------
-# Demo conversion, including ordinal numbers
-# -----------------------------------------------------------------------------
-set_typing_speed( 160 )
-
-paragraph()
-heading( "Date Conversions" )
-typer( "Mixing R code with definitions invites endless possibilities. " )
-typer( "Imagine someone racing to the " )
-typer( "`r#cms( v$location$breeder$storeys, ordinal=TRUE )` floor, whereby that " )
-typer( "ordinal stems from the Hatchery's storeys' definition. Or how about " )
-typer( "a complex timeline where dates are expressed in days relative to one " )
-typer( "point in time. Let's call this the *anchor date* and define it." )
-
-tab()
-home()
-typer( Key.SPACE )
-insert()
-rename_definition( "date" )
-insert()
-rename_definition( "anchor" )
-insert()
-rename_definition( "1969-10-29" )
-tab()
-
-paragraph()
-typer( "Next, set an R variable named `now` to the current date" )
-typer( "`r# now = format( Sys.time(), '%Y-%m-%d' ); ''`--- the empty single quotes " )
-typer( "prevent the date from appearing in the output document. " )
-
-paragraph()
-typer( "We set the anchor date to `r# annal()`, which was " )
-typer( "`r# elapsed( 0, days( v$date$anchor, format( Sys.time(), '%Y-%m-%d' ) ) )` " )
-typer( "ago from `r# format( as.Date( now ), '%B %d, %Y' )`. " )
-
-# -----------------------------------------------------------------------------
-# Demo CSV file import
-# -----------------------------------------------------------------------------
-paragraph()
-heading( "Tabular Data" )
-typer( "The following table shows average Canadian lifespans by birth " )
-typer( "year and sex:" )
-paragraph()
-typer( "`r# csv2md( '../data.csv', total=FALSE )`" )
-paragraph()
-typer( "Calling `csv2md` converts the comma-separated values in the spreadsheet " )
-typer( "to a table formatted using Markdown. The HTML preview pane changes the " )
-typer( "appearance of the resulting table. Using `../data.csv` instructs R to " )
-typer( "open `data.csv` from one directory above the *working directory*." )
-
-# -----------------------------------------------------------------------------
-# Demo HTML export
-# -----------------------------------------------------------------------------
-paragraph()
-heading( "Export" )
-typer( "Retrieve the output HTML by using the **Edit > Copy HTML** menu. Let's " )
-typer( "peek at the output." )
-wait( 2 )
-
-type( "e", Key.ALT )
-wait( 0.5 )
-down()
-wait( 0.25 )
-enter()
-wait( 0.25 )
-
-type( "a", Key.CTRL )
-wait( 0.25 )
-type( "v", Key.CTRL )
-wait( 5 )
-
-set_typing_speed( 40 )
-
-# Jump to page bottom (should already be there, but just in case)
-type( Key.END, Key.CTRL )
-recur( 3, typer, Key.PAGE_UP )
-type( Key.HOME, Key.CTRL )
-wait( 3 )
-
-set_typing_speed( 220 )
-type( "z", Key.CTRL )
-type( Key.END, Key.CTRL )
-
-paragraph()
-typer( "That's all for now, thank you!" )
-wait( 5 )
-
-# Delete the anchor date.
-tab()
-end()
-recur( 2, type, Key.UP )
-delete()
-tab()
sikuli/demo.sikuli/test.py
-from sikuli import *
-
-import sys
-import os
-
-def set_class_path():
- path_script = getBundlePath()
- dir_script = os.path.dirname( path_script )
- path_lib = dir_script + "/keycast/build/libs/keycast.jar"
-
- sys.path.append( path_lib )
-
-def launch():
- from com.whitemagicsoftware.keycast import KeyCast
- kc = KeyCast()
- kc.show()
-
-def main():
- set_class_path()
- launch()
-
-
-if __name__ == "__main__":
- main()
sikuli/editor.sikuli/1594187923258.png
Binary files differ
sikuli/editor.sikuli/editor.py
-# -----------------------------------------------------------------------------
-# Copyright 2020 White Magic Software, Ltd.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# This script contains helper functions used by the other scripts.
-#
-# Do not run this script.
-# -----------------------------------------------------------------------------
-
-from sikuli import *
-import sys
-import os
-from os.path import expanduser
-
-dir_home = expanduser( "~" )
-app_home = dir_home + "/bin"
-app_bin = app_home + "/scrivenvar.jar"
-
-wpm_typing_speed = 80
-
-# -----------------------------------------------------------------------------
-# Try to delete the file pointed to by the path variable. If there is no such
-# file, this will silently ignore the exception.
-# -----------------------------------------------------------------------------
-def rm( path ):
- try:
- os.remove( path )
- except:
- print "Ignored"
-
-# -----------------------------------------------------------------------------
-# Changes the current typing speed, where speed is given in words per minute.
-# -----------------------------------------------------------------------------
-def set_typing_speed( wpm ):
- global wpm_typing_speed
- wpm_typing_speed = wpm
-
-# -----------------------------------------------------------------------------
-# Creates a delay between keystrokes to emulate typing at a particular speed.
-# -----------------------------------------------------------------------------
-def random_wait():
- from time import sleep
- from random import uniform
- cpm = wpm_typing_speed * 5.1
- cps = cpm / 60.0
- ms_per_char = 1000.0 / cps
- ms_per_stroke = ms_per_char / 2.0
-
- noise = uniform( 0, ms_per_stroke / 2 )
- duration = (ms_per_stroke + noise ) / 1000
-
- sleep( duration )
-
-# -----------------------------------------------------------------------------
-# Repeats a function call, f, n times.
-# -----------------------------------------------------------------------------
-def recur( n, f, *args ):
- for i in range( n ):
- f( *args )
- random_wait()
-
-# -----------------------------------------------------------------------------
-# Emulate a typist who is typing in the given text.
-# -----------------------------------------------------------------------------
-def typer( text ):
- for c in text:
- type( c )
- random_wait()
-
-# -----------------------------------------------------------------------------
-# Type a line of text followed by typing the ENTER key.
-# -----------------------------------------------------------------------------
-def typeln( text ):
- typer( text )
- enter()
-
-# -----------------------------------------------------------------------------
-# Injects a definition.
-# -----------------------------------------------------------------------------
-def autoinsert():
- type( Key.SPACE, Key.CTRL )
- random_wait()
-
-# -----------------------------------------------------------------------------
-# Types the TAB key.
-# -----------------------------------------------------------------------------
-def tab():
- typer( Key.TAB )
-
-# -----------------------------------------------------------------------------
-# Types the ENTER key.
-# -----------------------------------------------------------------------------
-def enter():
- typer( Key.ENTER )
-
-# -----------------------------------------------------------------------------
-# Types the ESC key.
-# -----------------------------------------------------------------------------
-def esc():
- typer( Key.ESC )
-
-# -----------------------------------------------------------------------------
-# Types the DOWN arrow key.
-# -----------------------------------------------------------------------------
-def down():
- typer( Key.DOWN )
-
-# -----------------------------------------------------------------------------
-# Types the HOME key.
-# -----------------------------------------------------------------------------
-def home():
- typer( Key.HOME )
-
-# -----------------------------------------------------------------------------
-# Types the END key.
-# -----------------------------------------------------------------------------
-def end():
- typer( Key.END )
-
-# -----------------------------------------------------------------------------
-# Types the BACKSPACE key.
-# -----------------------------------------------------------------------------
-def backspace():
- typer( Key.BACKSPACE )
-
-# -----------------------------------------------------------------------------
-# Types the INSERT key, often to insert a new definition.
-# -----------------------------------------------------------------------------
-def insert():
- typer( Key.INSERT )
-
-# -----------------------------------------------------------------------------
-# Types the DELETE key, often to remove selected text.
-# -----------------------------------------------------------------------------
-def delete():
- typer( Key.DELETE )
-
-# -----------------------------------------------------------------------------
-# Moves the cursor one word to the right.
-# -----------------------------------------------------------------------------
-def skip_right():
- type( Key.RIGHT, Key.CTRL )
- random_wait()
-
-def select_word_right():
- type( Key.RIGHT, Key.CTRL + Key.SHIFT )
- random_wait()
-
-# -----------------------------------------------------------------------------
-# Types ENTER twice to begin a new paragraph.
-# -----------------------------------------------------------------------------
-def paragraph():
- recur( 2, enter )
- wait( 1.5 )
-
-# -----------------------------------------------------------------------------
-# Writes a heading to the document using the given text value as the content.
-# -----------------------------------------------------------------------------
-def heading( text ):
- typer( "# " + text )
- paragraph()
-
-# -----------------------------------------------------------------------------
-# Clicks the "Create" button to add a new definition.
-# -----------------------------------------------------------------------------
-def click_create():
- click("1594187923258.png")
- wait( .5 )
-
-# -----------------------------------------------------------------------------
-# Changes the text for the actively selected definition.
-# -----------------------------------------------------------------------------
-def rename_definition( text ):
- typer( Key.F2 )
- typer( text )
- enter()
- wait( .5 )
-
-# -----------------------------------------------------------------------------
-# Searches for the given text within the document.
-# -----------------------------------------------------------------------------
-def edit_find( text ):
- type( "f", Key.CTRL )
- typer( text )
- enter()
- wait( .25 )
- esc()
- wait( .5 )
-
-# -----------------------------------------------------------------------------
-# Searches for the next occurrence of the previous search term.
-# -----------------------------------------------------------------------------
-def edit_find_next():
- typer( Key.F3 )
- wait( .5 )
-
-# -----------------------------------------------------------------------------
-# Opens a dialog for selecting a file.
-# -----------------------------------------------------------------------------
-def file_open():
- type( "o", Key.CTRL )
- wait( 1 )
src/test/sikuli/.gitignore
+*.class
src/test/sikuli/README.md
+Sikuli is used for the following purposes:
+
+* Create application videos.
+* Create integration tests.
+
src/test/sikuli/demo.sikuli/1594187265140.png
Binary files differ
src/test/sikuli/demo.sikuli/1594592396134.png
Binary files differ
src/test/sikuli/demo.sikuli/1594593710440.png
Binary files differ
src/test/sikuli/demo.sikuli/1594593794335.png
Binary files differ
src/test/sikuli/demo.sikuli/1594594984108.png
Binary files differ
src/test/sikuli/demo.sikuli/1594689573764.png
Binary files differ
src/test/sikuli/demo.sikuli/demo.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Runs all scripts
+# -----------------------------------------------------------------------------
+
+import s01
+import s02
+import s03
+import s04
src/test/sikuli/demo.sikuli/s01.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# This script introduces the editor and its purpose.
+# -----------------------------------------------------------------------------
+from sikuli import *
+import sys
+
+if not "../editor.sikuli" in sys.path:
+ sys.path.append( "../editor.sikuli" )
+
+from editor import *
+
+# ---------------------------------------------------------------
+# Fresh start
+# ---------------------------------------------------------------
+rm( app_home + "/variables.yaml" )
+rm( app_home + "/untitled.md" )
+rm( dir_home + "/.scrivenvar" )
+
+# ---------------------------------------------------------------
+# Wait for application to launch
+# ---------------------------------------------------------------
+openApp( "java -jar " + app_bin )
+
+wait("1594187265140.png", 30)
+
+# Breathing room for video recording.
+wait( 4 )
+
+# ---------------------------------------------------------------
+# Introduction
+# ---------------------------------------------------------------
+set_typing_speed( 240 )
+
+heading( "What is this application?" )
+typer( "Well, this application is a text editor that supports interpolated definitions, ")
+typer( "a few different text formats, real-time preview, spell check ")
+typer( "as you tipe" )
+wait( 0.5 )
+recur( 3, backspace )
+typer( "ype, and R statements." )
+paragraph()
+wait( 1 )
+
+# ---------------------------------------------------------------
+# Definition demo
+# ---------------------------------------------------------------
+heading( "What are definitions?" )
+typer( "Watch. " )
+wait( .5 )
+
+# Focus the definition editor.
+click_create()
+recur( 4, tab )
+
+wait( .5 )
+rename_definition( "application" )
+
+insert()
+rename_definition( "title" )
+
+insert()
+rename_definition( "Scrivenvar" )
+
+# Set focus to the text editor.
+tab()
+
+typer( "The left-hand pane contains a nested, folder-like structure of names " )
+typer( "and values that are called *definitions*. " )
+wait( .5 )
+typer( "Such definitions can simplify updating documents. " )
+wait( 1 )
+
+edit_find( "this application" )
+typer( "$application.title$" )
+
+edit_find_next()
+typer( "$application.title$" )
+
+type( Key.END, Key.CTRL )
+
+typer( "The right-hand pane shows the result after having substituted definition " )
+typer( "values into the document." )
+
+paragraph()
+typer( "Now nobody wants to type definition names all the time. Instead, type any " )
+typer( "partial definition value followed by `Ctrl+Space`, such as: scr" )
+wait( 0.5 )
+autoinsert()
+wait( 1 )
+typer( ". *Much* better!" )
+paragraph()
+
+heading( "What is interpolation?" )
+typer( "Definition values can reference definition names. " )
+wait( .5 )
+typer( "The definition names act as placeholders. Substituting placeholders with " )
+typer( "their definition value is called *interpolation*. Let's see how it works." )
+wait( 2 )
src/test/sikuli/demo.sikuli/s02.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# This script demonstrates how to use interpolated strings.
+# -----------------------------------------------------------------------------
+from sikuli import *
+import sys
+
+if not "../editor.sikuli" in sys.path:
+ sys.path.append( "../editor.sikuli" )
+
+from editor import *
+
+# -----------------------------------------------------------------------------
+# Open sample chapter.
+# -----------------------------------------------------------------------------
+file_open()
+type( Key.UP, Key.ALT )
+wait( 1 )
+typer( Key.END )
+wait( 1 )
+enter()
+wait( 0.5 )
+enter()
+wait( 1 )
+
+# -----------------------------------------------------------------------------
+# Open the corresponding definition file.
+# -----------------------------------------------------------------------------
+file_open()
+recur( 2, down )
+wait( 1 )
+enter()
+wait( 1 )
+
+# -----------------------------------------------------------------------------
+# Edit the sample document.
+# -----------------------------------------------------------------------------
+set_typing_speed( 80 )
+
+type( Key.HOME, Key.CTRL )
+recur( 2, down )
+
+# Grey
+recur( 3, skip_right )
+autoinsert()
+
+# 34
+recur( 4, skip_right )
+autoinsert()
+
+# Central
+recur( 10, skip_right )
+autoinsert()
+
+# London
+skip_right()
+autoinsert()
+
+# Hatchery
+skip_right()
+autoinsert()
+
+# and Conditioning
+recur( 2, select_word_right )
+delete()
+
+# Centre
+skip_right()
+autoinsert()
+
+set_typing_speed( 220 )
+
+typer( " Let's interpolate those four definitions instead!" )
+wait( 4 )
+recur( 13, type, Key.BACKSPACE, Key.CTRL )
+recur( 9, backspace )
+
+set_typing_speed( 60 )
+
+typer( "name$" )
+wait( 2 )
+
+# Collapse all definitions
+tab()
+recur( 8, typer, Key.LEFT )
+
+# Expand to city
+recur( 4, typer, Key.RIGHT )
+
+# Jump to name
+recur( 2, down )
+recur( 2, typer, Key.RIGHT )
+
+# Open the text field to show the full value
+typer( Key.F2 )
+
+# Traverse the text field
+home()
+recur( 16, type, Key.RIGHT, Key.CTRL )
+esc()
+
+restore_typing_speed()
+
+tab()
+type( Key.HOME, Key.CTRL )
+edit_find( "Director" )
+autoinsert()
+
+edit_find_next()
+autoinsert()
+
+edit_find_next()
+typer( Key.RIGHT )
+recur( 2, delete )
+autoinsert()
+typer( "'s" )
+
+edit_find( "Hatcheries" )
+autoinsert()
+
+# and Conditioning
+recur( 2, select_word_right )
+delete()
+
+edit_find( "Central" )
+autoinsert()
+
+skip_right()
+autoinsert()
+
+typer( " How about a different city?" )
+wait( 2 )
+recur( 5, type, Key.BACKSPACE, Key.CTRL )
+wait( 1 )
+tab()
+typer( Key.F2 )
+typer( "Seattle" )
+enter()
+tab()
+wait( 2 )
+
+type( Key.END, Key.CTRL )
+paragraph()
+typer( "No?" )
+paragraph()
+
+tab()
+typer( Key.F2 )
+typer( "London" )
+enter()
+
+tab()
+typer( "Organizing definitions is left to your ")
+typer( "doub" )
+autoinsert()
+typer( " Good imagination." )
+tab()
+
+# Jump to "char" definition
+home()
+
+# Jump to "char.a.primary.name" definition
+recur( 6, typer, Key.RIGHT )
+
+# Jump to "char.a.primary.caste" definition
+down()
+typer( Key.RIGHT )
+
+# Jump to root-level "caste" definition
+recur( 7, down )
+
+# Reselect "super"
+recur( 5, typer, Key.RIGHT )
+wait( 2 )
+
+# Close the window, no save
+type( "w", Key.CTRL )
+wait( 0.5 )
+tab()
+wait( 0.5 )
+typer( Key.SPACE )
+wait( 1 )
src/test/sikuli/demo.sikuli/s03.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# This script introduces images and R.
+# -----------------------------------------------------------------------------
+from sikuli import *
+import sys
+
+if not "../editor.sikuli" in sys.path:
+ sys.path.append( "../editor.sikuli" )
+
+from editor import *
+
+set_typing_speed( 80 )
+
+file_open()
+type( Key.UP, Key.ALT )
+wait( 0.5 )
+home()
+wait( 0.25 )
+enter()
+wait( 1 )
+end()
+wait( 0.25 )
+enter()
+wait( 1 )
+
+set_typing_speed( 200 )
+
+paragraph()
+heading( "What text formats are supported?" )
+
+typer( "Scr" )
+autoinsert()
+typer( " supports Markdown, R Markdown, XML, and R XML; however, the software " )
+typer( "architecture enables it to easily add new formats. The following figure " )
+typer( "depicts the overall architecture: " )
+paragraph()
+typer( "![](../writing/images/architecture)" )
+paragraph()
+typer( "Many text editors can only open one type of plain text markup format that is " )
+typer( "only output as HTML. With a little more effort, text editors could support " )
+typer( "multiple input and output formats. Scr" )
+autoinsert()
+typer( " does so and goes one step further by introducing interpolated definitions." )
+paragraph()
+typer( "Kitten interlude:" )
+paragraph()
+typer( "![](https://i.imgur.com/jboueQH.jpg)" )
+paragraph()
+
+heading( "What is R?" )
+typer( "R is a programming language. You might have noticed a few potential grammar " )
+typer( "problems with direct substitution. Rules for possessive forms, numbers, and " )
+typer( "other quirks can be tackled using R." )
+
+# -----------------------------------------------------------------------------
+# Demo bootstrapping
+# -----------------------------------------------------------------------------
+
+# Jump to the end
+type( Key.END, Key.CTRL )
+paragraph()
+
+set_typing_speed( 300 )
+heading( "How is R used?" )
+typer( "R must be instructed where to find script files and what ones to load. The " )
+typer( "*working directory* is the full path to those R files; the *startup script* " )
+typer( "defines what R files to load. Both preferences must be changed before prose " )
+typer( "may be processed. Preferences can be opened using either the " )
+typeln( "**Edit > Preferences** menu or by pressing `Ctrl+Alt+s`. Here goes!" )
+wait( 2 )
+
+# -----------------------------------------------------------------------------
+# Select the R script directory
+# -----------------------------------------------------------------------------
+
+# Change the working directory by clicking "Browse"
+type( "s", Key.CTRL + Key.ALT )
+wait("1594592396134.png", 1)
+click("1594592396134.png")
+wait( 0.5 )
+
+# Navigate to and select the "r" directory
+type( Key.UP, Key.ALT )
+wait( 0.5 )
+end()
+wait( 0.5 )
+enter()
+wait( 0.5 )
+end()
+wait( 0.5 )
+type( Key.UP )
+wait( 0.5 )
+recur( 2, tab )
+wait( 0.5 )
+enter()
+wait( 1 )
+
+# -----------------------------------------------------------------------------
+# Set the R startup script instructions
+# -----------------------------------------------------------------------------
+
+wait("1594593710440.png", 5)
+click("1594593710440.png")
+
+set_typing_speed( 440 )
+
+typeln( "setwd( '$application.r.working.directory$' )" )
+typeln( "assign( 'anchor', '$date.anchor$', envir = .GlobalEnv )" )
+typeln( "source( 'pluralize.R' )" )
+typeln( "source( 'possessive.R' )" )
+typeln( "source( 'conversion.R' )" )
+typeln( "source( 'csv.R' )" )
+
+wait("1594593794335.png", 3)
+click("1594593794335.png")
+
+paragraph()
+set_typing_speed( 220 )
+
+typer( "R is now configured. The startup script and other R " )
+typer( "files can be found in the " )
+typer( "[repository](https://github.com/DaveJarvis/scrivenvar/tree/master/R). " )
+wait( 1.5 )
+
+# Wait for the browser to appear.
+wait("1594594984108.png", 5)
+click("1594594984108.png")
+
+wait( 5 )
+click("1594689573764.png")
+
+paragraph()
+typer( "Next, we'll see how definitions and R can work together." )
+wait( 2 )
src/test/sikuli/demo.sikuli/s04.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# This script demonstrates using R.
+# -----------------------------------------------------------------------------
+from sikuli import *
+import sys
+
+if not "../editor.sikuli" in sys.path:
+ sys.path.append( "../editor.sikuli" )
+
+from editor import *
+
+set_typing_speed( 220 )
+
+# -----------------------------------------------------------------------------
+# Open the demo text.
+# -----------------------------------------------------------------------------
+file_open()
+type( Key.UP, Key.ALT )
+wait( 0.5 )
+end()
+wait( 0.5 )
+enter()
+wait( 0.5 )
+down()
+wait( 0.5 )
+enter()
+wait( 2 )
+
+# -----------------------------------------------------------------------------
+# Re-open the corresponding definition file.
+# -----------------------------------------------------------------------------
+file_open()
+recur( 2, down )
+wait( 1 )
+enter()
+wait( 2 )
+
+# -----------------------------------------------------------------------------
+# Brief introduction to R
+# -----------------------------------------------------------------------------
+type( Key.HOME, Key.CTRL )
+end()
+paragraph()
+
+typer( "## Using R" )
+paragraph()
+typer( "Insert R code into documents as follows: `r# 1+1`. " )
+wait( 1.5 )
+typer( "Notice how the right-hand pane shows the computed result. I'll wait. " )
+wait( 3 )
+typer( "The syntax is: open backtick, r#, *computable expression*, close " )
+typer( "backtick. That expression can be any valid R statement. The status bar " )
+typer( "will provide clues when an R expression cannot be computed by the " )
+typer( "editor. `r# glitch`" )
+wait( 4 )
+recur( 11, backspace )
+typer( "Let's swap 34 storeys for a definition value and replace the number " )
+typer( "according to the Chicago Manual of Style (cms) rules." )
+
+# -----------------------------------------------------------------------------
+# Demo pluralization
+# -----------------------------------------------------------------------------
+set_typing_speed( 80 )
+
+edit_find( "34" )
+autoinsert()
+
+edit_find( "x(" )
+typer( "cms(" )
+
+edit_find( "storeys." )
+typer( "34." )
+autoinsert()
+edit_find( "x(" )
+typer( "pl( 'storey'," )
+wait( 4 )
+
+tab()
+rename_definition( "1" )
+wait( 4 )
+rename_definition( "142" )
+wait( 4 )
+rename_definition( "34" )
+wait( 4 )
+tab()
+
+# -----------------------------------------------------------------------------
+# Demo possessives (it, her, his, Director)
+# -----------------------------------------------------------------------------
+type( Key.HOME, Key.CTRL )
+edit_find( "Director" )
+autoinsert()
+edit_find_next()
+autoinsert()
+edit_find_next()
+autoinsert()
+type( Key.RIGHT )
+recur( 2, delete )
+autoinsert()
+home()
+edit_find( "x(" )
+typer( "pos(" )
+wait( 2 )
+
+tab()
+rename_definition( "Headmistress" )
+wait( 4 )
+rename_definition( "Director" )
+wait( 2 )
+tab()
+
+type( Key.END, Key.CTRL )
+paragraph()
+typer( "Other possessives: `r# pos( 'it' )`, `r# pos( 'her' )`, `r# pos( 'his' )`, " )
+typer( "and `r# pos( 'my' )`." )
+
+# -----------------------------------------------------------------------------
+# Demo conversion, including ordinal numbers
+# -----------------------------------------------------------------------------
+set_typing_speed( 160 )
+
+paragraph()
+heading( "Date Conversions" )
+typer( "Mixing R code with definitions invites endless possibilities. " )
+typer( "Imagine someone racing to the " )
+typer( "`r#cms( v$location$breeder$storeys, ordinal=TRUE )` floor, whereby that " )
+typer( "ordinal stems from the Hatchery's storeys' definition. Or how about " )
+typer( "a complex timeline where dates are expressed in days relative to one " )
+typer( "point in time. Let's call this the *anchor date* and define it." )
+
+tab()
+home()
+typer( Key.SPACE )
+insert()
+rename_definition( "date" )
+insert()
+rename_definition( "anchor" )
+insert()
+rename_definition( "1969-10-29" )
+tab()
+
+paragraph()
+typer( "Next, set an R variable named `now` to the current date" )
+typer( "`r# now = format( Sys.time(), '%Y-%m-%d' ); ''`--- the empty single quotes " )
+typer( "prevent the date from appearing in the output document. " )
+
+paragraph()
+typer( "We set the anchor date to `r# annal()`, which was " )
+typer( "`r# elapsed( 0, days( v$date$anchor, format( Sys.time(), '%Y-%m-%d' ) ) )` " )
+typer( "ago from `r# format( as.Date( now ), '%B %d, %Y' )`. " )
+
+# -----------------------------------------------------------------------------
+# Demo CSV file import
+# -----------------------------------------------------------------------------
+paragraph()
+heading( "Tabular Data" )
+typer( "The following table shows average Canadian lifespans by birth " )
+typer( "year and sex:" )
+paragraph()
+typer( "`r# csv2md( '../data.csv', total=FALSE )`" )
+paragraph()
+typer( "Calling `csv2md` converts the comma-separated values in the spreadsheet " )
+typer( "to a table formatted using Markdown. The HTML preview pane changes the " )
+typer( "appearance of the resulting table. Using `../data.csv` instructs R to " )
+typer( "open `data.csv` from one directory above the *working directory*." )
+
+# -----------------------------------------------------------------------------
+# Demo HTML export
+# -----------------------------------------------------------------------------
+paragraph()
+heading( "Export" )
+typer( "Retrieve the output HTML by using the **Edit > Copy HTML** menu. Let's " )
+typer( "peek at the output." )
+wait( 2 )
+
+type( "e", Key.ALT )
+wait( 0.5 )
+down()
+wait( 0.25 )
+enter()
+wait( 0.25 )
+
+type( "a", Key.CTRL )
+wait( 0.25 )
+type( "v", Key.CTRL )
+wait( 5 )
+
+set_typing_speed( 40 )
+
+# Jump to page bottom (should already be there, but just in case)
+type( Key.END, Key.CTRL )
+recur( 3, typer, Key.PAGE_UP )
+type( Key.HOME, Key.CTRL )
+wait( 3 )
+
+set_typing_speed( 220 )
+type( "z", Key.CTRL )
+type( Key.END, Key.CTRL )
+
+paragraph()
+typer( "That's all for now, thank you!" )
+wait( 5 )
+
+# Delete the anchor date.
+tab()
+end()
+recur( 2, type, Key.UP )
+delete()
+tab()
src/test/sikuli/demo.sikuli/test.py
+from sikuli import *
+
+import sys
+import os
+
+def set_class_path():
+ path_script = getBundlePath()
+ dir_script = os.path.dirname( path_script )
+ path_lib = dir_script + "/keycast/build/libs/keycast.jar"
+
+ sys.path.append( path_lib )
+
+def launch():
+ from com.whitemagicsoftware.keycast import KeyCast
+ kc = KeyCast()
+ kc.show()
+
+def main():
+ set_class_path()
+ launch()
+
+
+if __name__ == "__main__":
+ main()
src/test/sikuli/editor.sikuli/1594187923258.png
Binary files differ
src/test/sikuli/editor.sikuli/editor.py
+# -----------------------------------------------------------------------------
+# Copyright 2020 White Magic Software, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# This script contains helper functions used by the other scripts.
+#
+# Do not run this script.
+# -----------------------------------------------------------------------------
+
+from sikuli import *
+import sys
+import os
+from os.path import expanduser
+
+dir_home = expanduser( "~" )
+app_home = dir_home + "/bin"
+app_bin = app_home + "/scrivenvar.jar"
+
+wpm_typing_speed = 80
+
+# -----------------------------------------------------------------------------
+# Try to delete the file pointed to by the path variable. If there is no such
+# file, this will silently ignore the exception.
+# -----------------------------------------------------------------------------
+def rm( path ):
+ try:
+ os.remove( path )
+ except:
+ print "Ignored"
+
+# -----------------------------------------------------------------------------
+# Changes the current typing speed, where speed is given in words per minute.
+# -----------------------------------------------------------------------------
+def set_typing_speed( wpm ):
+ global wpm_typing_speed
+ wpm_typing_speed = wpm
+
+# -----------------------------------------------------------------------------
+# Creates a delay between keystrokes to emulate typing at a particular speed.
+# -----------------------------------------------------------------------------
+def random_wait():
+ from time import sleep
+ from random import uniform
+ cpm = wpm_typing_speed * 5.1
+ cps = cpm / 60.0
+ ms_per_char = 1000.0 / cps
+ ms_per_stroke = ms_per_char / 2.0
+
+ noise = uniform( 0, ms_per_stroke / 2 )
+ duration = (ms_per_stroke + noise ) / 1000
+
+ sleep( duration )
+
+# -----------------------------------------------------------------------------
+# Repeats a function call, f, n times.
+# -----------------------------------------------------------------------------
+def recur( n, f, *args ):
+ for i in range( n ):
+ f( *args )
+ random_wait()
+
+# -----------------------------------------------------------------------------
+# Emulate a typist who is typing in the given text.
+# -----------------------------------------------------------------------------
+def typer( text ):
+ for c in text:
+ type( c )
+ random_wait()
+
+# -----------------------------------------------------------------------------
+# Type a line of text followed by typing the ENTER key.
+# -----------------------------------------------------------------------------
+def typeln( text ):
+ typer( text )
+ enter()
+
+# -----------------------------------------------------------------------------
+# Injects a definition.
+# -----------------------------------------------------------------------------
+def autoinsert():
+ type( Key.SPACE, Key.CTRL )
+ random_wait()
+
+# -----------------------------------------------------------------------------
+# Types the TAB key.
+# -----------------------------------------------------------------------------
+def tab():
+ typer( Key.TAB )
+
+# -----------------------------------------------------------------------------
+# Types the ENTER key.
+# -----------------------------------------------------------------------------
+def enter():
+ typer( Key.ENTER )
+
+# -----------------------------------------------------------------------------
+# Types the ESC key.
+# -----------------------------------------------------------------------------
+def esc():
+ typer( Key.ESC )
+
+# -----------------------------------------------------------------------------
+# Types the DOWN arrow key.
+# -----------------------------------------------------------------------------
+def down():
+ typer( Key.DOWN )
+
+# -----------------------------------------------------------------------------
+# Types the HOME key.
+# -----------------------------------------------------------------------------
+def home():
+ typer( Key.HOME )
+
+# -----------------------------------------------------------------------------
+# Types the END key.
+# -----------------------------------------------------------------------------
+def end():
+ typer( Key.END )
+
+# -----------------------------------------------------------------------------
+# Types the BACKSPACE key.
+# -----------------------------------------------------------------------------
+def backspace():
+ typer( Key.BACKSPACE )
+
+# -----------------------------------------------------------------------------
+# Types the INSERT key, often to insert a new definition.
+# -----------------------------------------------------------------------------
+def insert():
+ typer( Key.INSERT )
+
+# -----------------------------------------------------------------------------
+# Types the DELETE key, often to remove selected text.
+# -----------------------------------------------------------------------------
+def delete():
+ typer( Key.DELETE )
+
+# -----------------------------------------------------------------------------
+# Moves the cursor one word to the right.
+# -----------------------------------------------------------------------------
+def skip_right():
+ type( Key.RIGHT, Key.CTRL )
+ random_wait()
+
+def select_word_right():
+ type( Key.RIGHT, Key.CTRL + Key.SHIFT )
+ random_wait()
+
+# -----------------------------------------------------------------------------
+# Types ENTER twice to begin a new paragraph.
+# -----------------------------------------------------------------------------
+def paragraph():
+ recur( 2, enter )
+ wait( 1.5 )
+
+# -----------------------------------------------------------------------------
+# Writes a heading to the document using the given text value as the content.
+# -----------------------------------------------------------------------------
+def heading( text ):
+ typer( "# " + text )
+ paragraph()
+
+# -----------------------------------------------------------------------------
+# Clicks the "Create" button to add a new definition.
+# -----------------------------------------------------------------------------
+def click_create():
+ click("1594187923258.png")
+ wait( .5 )
+
+# -----------------------------------------------------------------------------
+# Changes the text for the actively selected definition.
+# -----------------------------------------------------------------------------
+def rename_definition( text ):
+ typer( Key.F2 )
+ typer( text )
+ enter()
+ wait( .5 )
+
+# -----------------------------------------------------------------------------
+# Searches for the given text within the document.
+# -----------------------------------------------------------------------------
+def edit_find( text ):
+ type( "f", Key.CTRL )
+ typer( text )
+ enter()
+ wait( .25 )
+ esc()
+ wait( .5 )
+
+# -----------------------------------------------------------------------------
+# Searches for the next occurrence of the previous search term.
+# -----------------------------------------------------------------------------
+def edit_find_next():
+ typer( Key.F3 )
+ wait( .5 )
+
+# -----------------------------------------------------------------------------
+# Opens a dialog for selecting a file.
+# -----------------------------------------------------------------------------
+def file_open():
+ type( "o", Key.CTRL )
+ wait( 1 )
tex/build.sh
-#!/usr/bin/env bash
-
-#
-# Example command-line to be invoked directly by the application.
-#
-
-context --environment="env,setups,entities,style,classes" "$1.xml"
-
tex/classes.tex
-\defineframedtext[projection][
- style=tt,
- width=\textwidth,
-]
-
tex/entities.tex
-% Map XHTML document entities to ConTeXt symbols and TeX macros.
-
-\xmltexentity{ldquo}{\symbol[leftquotation]{}}
-\xmltexentity{rdquo}{\symbol[rightquotation]{}}
-\xmltexentity{rsquo}{\quotesingle{}}
-\xmltexentity{mdash}{\emdash{}}
-\xmltexentity{ndash}{\endash{}}
-\xmltexentity{hellip}{\dots{}}
-
tex/env.tex
-% Defines any macros required by all other TeX files.
-
-\define[2]\href{%
- \begingroup
- \setupinteraction[
- style=normal,
- color=steelblue,
- ]%
- \goto{\color[blue]{#1}}[url(#2)]%
- \endgroup%
-}
-
tex/setups.tex
-% XML setups map ConTeXt commands to HTML elements.
-
-\startxmlsetups xml:xhtml
- % Do not typeset the HTML document's header title element.
- \xmlsetsetup{\xmldocument}{*}{-}
-
- % Document elements
- \xmlsetsetup{\xmldocument}{html|body}{xml:*}
-
- % Header elements
- \xmlsetsetup{\xmldocument}{h1|h2|h3|h4|h5|h6}{xml:*}
-
- % Block elements
- \xmlsetsetup{\xmldocument}{p|q|blockquote|div}{xml:*}
-
- % List elements
- \xmlsetsetup{\xmldocument}{ul|ol|li|dl|dt|dd}{xml:*}
-
- % Break elements
- \xmlsetsetup{\xmldocument}{hr|br}{xml:*}
-
- % Inline elements
- \xmlsetsetup{\xmldocument}{span|em|b|strong|a|sup|sub|code|img}{xml:*}
-
- % TeX elements
- \xmlsetsetup{\xmldocument}{tex}{xml:*}
-\stopxmlsetups
-
-\startxmlsetups xml:html
- \xmlflush{#1}
-\stopxmlsetups
-
-\startxmlsetups xml:body
- \xmlflush{#1}
-\stopxmlsetups
-
-\startxmlsetups xml:h1
- \chapter{\xmlflush{#1}}
-\stopxmlsetups
-
-\startxmlsetups xml:h2
- \section{\xmlflush{#1}}
-\stopxmlsetups
-
-\startxmlsetups xml:h3
- \subsection{\xmlflush{#1}}
-\stopxmlsetups
-
-% Paragraphs are followed by a paragraph break.
-\startxmlsetups xml:p
- \xmlflush{#1}\par
-\stopxmlsetups
-
-\startxmlsetups xml:ul
- \startitemize
- \xmlflush{#1}
- \stopitemize
-\stopxmlsetups
-
-\startxmlsetups xml:li
- \startitem \xmlflush{#1} \stopitem
-\stopxmlsetups
-
-% Requires the \href macro.
-\startxmlsetups xml:a
- \href{\xmlflush{#1}}{\xmlatt{#1}{href}}
-\stopxmlsetups
-
-\startxmlsetups xml:tex
- \xmlflushcontext{#1}
-\stopxmlsetups
-
-% Emphasized text is italicized, typically.
-\startxmlsetups xml:em
- \dontleavehmode{\em\xmlflush{#1}}
-\stopxmlsetups
-
-% Strong text is bolded, typically.
-\startxmlsetups xml:strong
- \dontleavehmode{\bf\xmlflush{#1}}
-\stopxmlsetups
-
-\startxmlsetups xml:img
- \starttexcode
- \placefigure{}{%
- \externalfigure[\xmlatt{#1}{src}][conversion=mp]%
- }
- \stoptexcode
-\stopxmlsetups
-
-\startxmlsetups xml:q
- \quotation{\xmlflush{#1}}
-\stopxmlsetups
-
-% Map arbitrary div classes, defined by fenced divs.
-\startxmlsetups xml:div
- \start[\xmlatt{#1}{class}]
- \xmlflush{#1}
- \stop
-\stopxmlsetups
-
-\xmlregistersetup{xml:xhtml}
-
tex/style.tex
-\usetypescript[termes]
-\setupbodyfont[termes, 11pt]
-
-\setupbodyfontenvironment[default][em=italic]
-
-\setupinteraction[state=start]
-
-\setuphead[chapter][
- page=yes,
- header=empty,
- after={\blank[line]}
-]
-
-\setuphead[section,subsection][
- page=no,
- number=yes,
- before={\blank[big]},
- after={\blank[line]}
-]
-
-\setupindenting[medium, yes]
-
-\setupexternalfigures[
- order={svg,pdf,png},
- maxwidth=\makeupwidth,
- width=\makeupwidth,
-]
-
-% Force images to flow exactly where they fall in the text, captionlessly.
-\setupfloat[figure][default={force,none}]
-
-% Indent the paragraph following each image.
-\setupfloats[indentnext=yes]
-
-\definesymbol[bullet][•]
-
-% Reduce the spacing around bullets.
-\setupitemgroup[itemize][1][packed,paragraph][
- leftmargin=2em,
- distance=\zeropoint,
- symbol=bullet,
-]
-
themes/build.sh
+#!/usr/bin/env bash
+
+#
+# Example command-line to be invoked directly by the application.
+#
+
+context --environment="env,setups,entities,style,classes" "$1.xml"
+
themes/classes.tex
+\defineframedtext[projection][
+ style=tt,
+ width=\textwidth,
+]
+
themes/entities.tex
+% Map XHTML document entities to ConTeXt symbols and TeX macros.
+
+\xmltexentity{ldquo}{\symbol[leftquotation]{}}
+\xmltexentity{rdquo}{\symbol[rightquotation]{}}
+\xmltexentity{rsquo}{\quotesingle{}}
+\xmltexentity{mdash}{\emdash{}}
+\xmltexentity{ndash}{\endash{}}
+\xmltexentity{hellip}{\dots{}}
+
themes/env.tex
+% Defines any macros required by all other TeX files.
+
+\define[2]\href{%
+ \begingroup
+ \setupinteraction[
+ style=normal,
+ color=steelblue,
+ ]%
+ \goto{\color[blue]{#1}}[url(#2)]%
+ \endgroup%
+}
+
themes/setups.tex
+% XML setups map ConTeXt commands to HTML elements.
+
+\startxmlsetups xml:xhtml
+ % Do not typeset the HTML document's header title element.
+ \xmlsetsetup{\xmldocument}{*}{-}
+
+ % Document elements
+ \xmlsetsetup{\xmldocument}{html|body}{xml:*}
+
+ % Header elements
+ \xmlsetsetup{\xmldocument}{h1|h2|h3|h4|h5|h6}{xml:*}
+
+ % Block elements
+ \xmlsetsetup{\xmldocument}{p|q|blockquote|div}{xml:*}
+
+ % List elements
+ \xmlsetsetup{\xmldocument}{ul|ol|li|dl|dt|dd}{xml:*}
+
+ % Break elements
+ \xmlsetsetup{\xmldocument}{hr|br}{xml:*}
+
+ % Inline elements
+ \xmlsetsetup{\xmldocument}{span|em|b|strong|a|sup|sub|code|img}{xml:*}
+
+ % TeX elements
+ \xmlsetsetup{\xmldocument}{tex}{xml:*}
+\stopxmlsetups
+
+\startxmlsetups xml:html
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:body
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:h1
+ \chapter{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:h2
+ \section{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:h3
+ \subsection{\xmlflush{#1}}
+\stopxmlsetups
+
+% Paragraphs are followed by a paragraph break.
+\startxmlsetups xml:p
+ \xmlflush{#1}\par
+\stopxmlsetups
+
+\startxmlsetups xml:ul
+ \startitemize
+ \xmlflush{#1}
+ \stopitemize
+\stopxmlsetups
+
+\startxmlsetups xml:li
+ \startitem \xmlflush{#1} \stopitem
+\stopxmlsetups
+
+% Requires the \href macro.
+\startxmlsetups xml:a
+ \href{\xmlflush{#1}}{\xmlatt{#1}{href}}
+\stopxmlsetups
+
+\startxmlsetups xml:tex
+ \xmlflushcontext{#1}
+\stopxmlsetups
+
+% Emphasized text is italicized, typically.
+\startxmlsetups xml:em
+ \dontleavehmode{\em\xmlflush{#1}}
+\stopxmlsetups
+
+% Strong text is bolded, typically.
+\startxmlsetups xml:strong
+ \dontleavehmode{\bf\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:img
+ \starttexcode
+ \placefigure{}{%
+ \externalfigure[\xmlatt{#1}{src}][conversion=mp]%
+ }
+ \stoptexcode
+\stopxmlsetups
+
+\startxmlsetups xml:q
+ \quotation{\xmlflush{#1}}
+\stopxmlsetups
+
+% Map arbitrary div classes, defined by fenced divs.
+\startxmlsetups xml:div
+ \start[\xmlatt{#1}{class}]
+ \xmlflush{#1}
+ \stop
+\stopxmlsetups
+
+\xmlregistersetup{xml:xhtml}
+
themes/style.tex
+\usetypescript[termes]
+\setupbodyfont[termes, 11pt]
+
+\setupbodyfontenvironment[default][em=italic]
+
+\setupinteraction[state=start]
+
+\setuphead[chapter][
+ page=yes,
+ header=empty,
+ after={\blank[line]}
+]
+
+\setuphead[section,subsection][
+ page=no,
+ number=yes,
+ before={\blank[big]},
+ after={\blank[line]}
+]
+
+\setupindenting[medium, yes]
+
+\setupexternalfigures[
+ order={svg,pdf,png},
+ maxwidth=\makeupwidth,
+ width=\makeupwidth,
+]
+
+% Force images to flow exactly where they fall in the text, captionlessly.
+\setupfloat[figure][default={force,none}]
+
+% Indent the paragraph following each image.
+\setupfloats[indentnext=yes]
+
+\definesymbol[bullet][•]
+
+% Reduce the spacing around bullets.
+\setupitemgroup[itemize][1][packed,paragraph][
+ leftmargin=2em,
+ distance=\zeropoint,
+ symbol=bullet,
+]
+
Delta1177 lines added, 1172 lines removed, 5-line increase