| Author | DaveJarvis <email> |
|---|---|
| Date | 2021-03-31 22:46:47 GMT-0700 |
| Commit | fb0ed952923fd2a681af7a8d2098e0d8c965634c |
| Parent | 1a14cfd |
| -*.class | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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 | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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 ) | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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 ) | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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( "" ) | ||
| -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( "" ) | ||
| -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 ) | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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() | ||
| -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() | ||
| -# ----------------------------------------------------------------------------- | ||
| -# 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 ) | ||
| +*.class | ||
| +Sikuli is used for the following purposes: | ||
| + | ||
| +* Create application videos. | ||
| +* Create integration tests. | ||
| + | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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 | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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 ) | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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 ) | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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( "" ) | ||
| +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( "" ) | ||
| +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 ) | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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() | ||
| +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() | ||
| +# ----------------------------------------------------------------------------- | ||
| +# 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 ) | ||
| -#!/usr/bin/env bash | ||
| - | ||
| -# | ||
| -# Example command-line to be invoked directly by the application. | ||
| -# | ||
| - | ||
| -context --environment="env,setups,entities,style,classes" "$1.xml" | ||
| - | ||
| -\defineframedtext[projection][ | ||
| - style=tt, | ||
| - width=\textwidth, | ||
| -] | ||
| - | ||
| -% 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{}} | ||
| - | ||
| -% 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% | ||
| -} | ||
| - | ||
| -% 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} | ||
| - | ||
| -\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, | ||
| -] | ||
| - | ||
| +#!/usr/bin/env bash | ||
| + | ||
| +# | ||
| +# Example command-line to be invoked directly by the application. | ||
| +# | ||
| + | ||
| +context --environment="env,setups,entities,style,classes" "$1.xml" | ||
| + | ||
| +\defineframedtext[projection][ | ||
| + style=tt, | ||
| + width=\textwidth, | ||
| +] | ||
| + | ||
| +% 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{}} | ||
| + | ||
| +% 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% | ||
| +} | ||
| + | ||
| +% 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} | ||
| + | ||
| +\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, | ||
| +] | ||
| + | ||
| Delta | 1177 lines added, 1172 lines removed, 5-line increase |
|---|