Skip to content

REPL Console

mattirn edited this page Oct 29, 2020 · 7 revisions

Builtin support for console variables, scripts, custom pipes, widgets and object printing.

Integration with JVM scripting languages

Interfaces

  1. ScriptEngine manages JVM scripting language variables and script execution.
  2. ConsoleEngine extends CommandRegistry interface. Manages console variables, console script execution and object printing. ConsoleEngineImpl have implementation of console commands: show, del, prnt, pipe, alias, unalias and slurp.
  3. SystemRegistry extends CommandRegistry interface. Aggregates CommandRegisteries, compile command pipe lines and dispatch command executions to the command registeries. SystemRegistryImpl implements commands: help and exit .

Variables

Reserved variable names

  • PATH a list of directories from where scripts are searched
  • NANORC nanorc configuration file
  • PRNT_OPTIONS prnt command default options
  • CONSOLE_OPTIONS console options
  • _ the last result of the command execution
  • exception the last exception
  • output redirected print output if command also returns value
  • _args command parameter list for the groovy script. This is to be used inside a script.
  • _buffer closure that will call lineReader.getBuffer(), available for widget functions.
  • _reader lineReader, available for widget functions
  • _widget closure that will call lineReader.callWidget(), available for widget functions
  • _widgetFunction function that will be launched when executing widget
  • _pipe<N> temporary variables used to execute command pipe line
  • _executionResult command execution result
  • _return used to return execution result from console script

Used variable name conventions

  1. Variables whose name start with underscore character _ are temporary variables that are deleted in REPL-loop.
  2. Variables whose name is in CAMEL_CASE format are not deleted when using wild card in delete command like del *

Variable expansion

Variable expansion substitutes variable reference with its value. Examples:

groovy-repl> # create a map and print it
groovy-repl> user=[name:'Pippo',age:10]
groovy-repl> prnt $user
name Pippo
age  10
groovy-repl> prnt ${user}.name
Pippo

Note that command object parameters can also be written directly using either Groovy object notation or JSON:

groovy-repl> prnt -s JSON [user:'pippo',age:10]
{
    "user": "pippo",
    "age": 10
}
groovy-repl> prnt -s JSON {user:pippo,age:10}
{
    "user": "pippo",
    "age": 10
}

Scripts

Implementation brings in life two type of scripts: console and groovy scripts.

Console scripts

Script parameters are accessed inside a script as usual using the variables $1, $2, $3, and so on. In console script application commands are entered just like you do interactively. Note that inside a code block command line must be either of the forms :command arg1 arg2 or var=:command arg1 arg2. Use exit command to exit and return value from script. Console scripts have two built-in options: -? for script help and -v for verbose execution. Console script output cannot be redirected.

Groovy scripts

A temporary list variable _args will be created to assign command parameters to the script. Application commands can be executed inside a script using a statements like SystemRegistry.get().invoke('prnt', '-s', 'JSON', map). Groovy scripts have built-in help option -?.

Pipes and output redirection

The main purpose of the pipes is to make things more concise and create a more familiar REPL console for those who have used to work in bash/zsh. Pipe operator implementation has been inspired by Ammonite.

Builtin pipe operators

Output redirection

Command output/return value can be redirected to variable by entering command like:

groovy-repl> resp=widget -l
groovy-repl> resp
_tailtip-accept-line (_tailtip-accept-line)
_tailtip-backward-delete-char (_tailtip-backward-delete-char)
_tailtip-delete-char (_tailtip-delete-char)
_tailtip-expand-or-complete (_tailtip-expand-or-complete)
_tailtip-redisplay (_tailtip-redisplay)
_tailtip-self-insert (_tailtip-self-insert)
_tailtip-toggle (_tailTipToggle)
tailtip-toggle (tailtip-toggle)
tailtip-window (tailtip-window)
test-widget (_testWidget)

Note that no spaces are allowed between variable/command and equal sign.

Command output can be redirected to file using standard redirection operators > and >>.

Logical pipe operators

The and operator (&&) would execute the second command only, if the execution of first command succeeds. The or Operator (||) allows you to execute the second command only if the execution of first command fails.

Note that all the pipe operators must be enclosed by space characters and the command line cannot be enclosed by parenthesis or quotes.

groovy-repl> # this is evaluated by the console engine 
groovy-repl> true && false || true
true
false
true
groovy-repl> # the command lines below are evaluated entirely by Groovy engine 
groovy-repl> (true && false || true)
true
groovy-repl> true&&false||true
true

Flip pipe operator

The flip pipe operator |; flips around the command and argument:

groovy-repl> widget -l |; prnt -s JSON
[
    "_tailtip-accept-line (_tailtip-accept-line)",
    "_tailtip-backward-delete-char (_tailtip-backward-delete-char)",
    "_tailtip-delete-char (_tailtip-delete-char)",
    "_tailtip-expand-or-complete (_tailtip-expand-or-complete)",
    "_tailtip-redisplay (_tailtip-redisplay)",
    "_tailtip-self-insert (_tailtip-self-insert)",
    "_tailtip-toggle (_tailTipToggle)",
    "hello-world (helloWorld)",
    "tailtip-toggle (tailtip-toggle)",
    "tailtip-window (tailtip-window)",
    "test-widget (_testWidget)"
]

Named pipe operator

Actually only reserved pipe operator | that will be used by custom named pipes and pipe line aliases.

Custom pipe operators

Pipe operator name convention: If pipe operator name contains only alphanumeric characters it is named pipe operator and it will be used with operator |.

#
# custom Groovy pipes
#
pipe |.  '.collect{' '}'
pipe |:  '.collectEntries{' '}'
pipe |:: '.collectMany{' '}'
pipe |?  '.findAll{' '}'
pipe |?1 '.find{' '}'
pipe |&  '.' ' '
#
# named pipe and two pipe line aliases
#
pipe grep '.collect{it.toString()}.findAll{it=~/' '/}'
alias null '|& identity{}' 
alias xargs '|; %{0} %{1} %{2} %{3} %{4} %{5} %{6} %{7} %{8} %{9}'

Note that pipe line alias value starts with known pipe operator.

Widgets

In widget function you will have available temporary variables: _reader (lineReader), _buffer (closure that will call lineReader.getBuffer()) and _widget (closure that will call lineReader.callWidget()).

#
# create test-widget and bind it to ctrl-alt-x
# It will read widget name from buffer and execute it
#
def testWidget() {
    def name = _buffer().toString().split('\\s+')[0]
    _widget "$name"
}
widget -N test-widget testWidget 
keymap '^[^x' test-widget

See the same example using Java.

REPL Demo

REPL demo implemention and sample scripts. To run the demo, simply use the following command after having build JLine

./build repl