The Data REPL

General design

An extensible "Data REPL" is provided to make directly interacting with the Data.toml a bit more convenient. It can be entered by pressing } on an empty julia> REPL line.

julia> # type }
data> help
 Command  Action
 help     Display help information on the available commands

The foremost data collection is also listed in the prompt in much the same manner as (environment) pkg>, i.e.

(⋅) data>        # No currently loaded data collections
(example) data>  # The top data collection is "example"

Commands (and sub-commands) can be triggered by typing them out in full (i.e. cmd args...) but also abbreviated up to the unique stem. For instance if cmd is the only command starting with c, then it can be called with any of

  • data> cmd args...
  • data> cm args...
  • data> c args...

However, should a command conflict also exist, then c is no longer a unique stem and so c args... will produce an error message like so:

data> c args...
 ! Multiple matching Data REPL commands: cmd, conflict

The help command

help is implemented specially in the Data REPL. It can be invoked normally (i.e. help cmd) but also with ? prefix (i.e. ?cmd). Furthermore, all commands with sub-commands with automatically have a help sub-command added. Overall, help supports the following usage patterns.

data> help             # List available commands.
data> help cmd         # Obtain the help for cmd, or
data> help cmd         # list available sub-command (if applicable).
data> ?cmd             # Obtain the help for cmd.
data> help cmd subcmd  # Obtain the help for subcmd.
data> ?cmd subcmd      # Obtain the help for subcmd.
data> cmd help subcmd  # Obtain the help for subcmd.
data> cmd ?subcmd      # Obtain the help for subcmd.

Extending the Data REPL

Registering commands

To register a command, one simply needs to push a ReplCmd onto REPL_CMDS.


A command that can be used in the Data REPL (accessible through '}').

A ReplCmd must have a:

  • name, a symbol designating the command keyword.
  • trigger, a string used as the command trigger (defaults to String(name)).
  • description, a short overview of the functionality as a string or displayable object.
  • execute, either a list of sub-ReplCmds, or a function which will perform the command's action. The function must take a single argument, the rest of the command as an AbstractString (for example, 'cmd arg1 arg2' will call the execute function with "arg1 arg2").


ReplCmd{name::Symbol}(trigger::String, description::Any, execute::Function)
ReplCmd{name::Symbol}(description::Any, execute::Function)
ReplCmd(name::Union{Symbol, String}, trigger::String, description::Any, execute::Function)
ReplCmd(name::Union{Symbol, String}, description::Any, execute::Function)


ReplCmd(:echo, "print the argument", identity)
ReplCmd(:addone, "return the input plus one", v -> 1 + parse(Int, v))
ReplCmd(:math, "A collection of basic integer arithmetic",
    [ReplCmd(:add, "a + b + ...", nums -> sum(parse.(Int, split(nums))))],
     ReplCmd(:mul, "a * b * ...", nums -> prod(parse.(Int, split(nums)))))


help(::ReplCmd) # -> print detailed help
allcompletions(::ReplCmd) # -> list all candidates
completions(::ReplCmd, sofar::AbstractString) # -> list relevant candidates


As hinted by the ReplCmd docstring, completions can be implemented by implementing completions(::ReplCmd{:CMD_ID}, sofar::AbstractString) or allcompletions.

completions(r::ReplCmd, sofar::AbstractString)

Obtain a list of String completion candidates based on sofar. All candidates should begin with sofar.

Should this function not be implemented for the specific ReplCmd r, allcompletions(r) will be called and filter to candidates that begin with sofar.

If r has subcommands, then the subcommand prefix will be removed and completions re-called on the relevant subcommand.


Obtain all possible String completion candidates for r. This defaults to the empty vector String[].

allcompletions is only called when completions(r, sofar::AbstractString) is not implemented.


Helper functions

To create a pleasant user interface, a number of utility functions are provided.

prompt(question::AbstractString, default::AbstractString="",
       allowempty::Bool=false, cleardefault::Bool=true,

Interactively ask question and return the response string, optionally with a default value. If multiline is true, RET must be pressed twice consecutively to submit a value.

Unless allowempty is set an empty response is not accepted. If cleardefault is set, then an initial backspace will clear the default value.

The prompt supports the following line-edit-y keys:

  • left arrow
  • right arrow
  • home
  • end
  • delete forwards
  • delete backwards


julia> prompt("What colour is the sky? ")
What colour is the sky? Blue
prompt_char(question::AbstractString, options::Vector{Char},
            default::Union{Char, Nothing}=nothing)

Interactively ask question, only accepting options keys as answers. All keys are converted to lower case on input. If default is not nothing and 'RET' is hit, then default will be returned.

Should '^C' be pressed, an InterruptException will be thrown.

confirm_yn(question::AbstractString, default::Bool=false)

Interactively ask question and accept y/Y/n/N as the response. If any other key is pressed, then default will be taken as the response. A " [y/n]: " string will be appended to the question, with y/n capitalised to indicate the default value.


julia> confirm_yn("Do you like chocolate?", true)
Do you like chocolate? [Y/n]: y

Read the next 'word' from input. If input starts with a quote, this is the unescaped text between the opening and closing quote. Other wise this is simply the next word.

Returns a tuple of the form (word, rest).


julia> peelword("one two")
("one", "two")

julia> peelword(""one two" three")
("one two", "three")

Simple example

In the below example we will extend the Data REPL by adding a command cowsay which simply call the (assumed to be installed) system cowsay executable.

function cowsay_repl(input::AbstractString)
    if isempty(input)
        confirm_yn("Are you ready to hear your fortune?", true) &&
            cowsay_repl(read(`fortune`, String))
        println(read(`cowsay $input`, String))

push!(REPL_CMDS, ReplCmd(:cowsay3,
                         "Hear what the cow has to say
\n Call with no argument to obtain a fortune.",

DataToolkitBase.allcompletions(::ReplCmd{:cowsay}) =
    ["Improve your data management with DataToolkits & co."]

If you enter the Data REPL, you will be able to note that:

  • cowsay is listed in data> help
  • running cowsay with no arguments results in a Y/n prompt to show a fortune
  • pressing TAB after cowsay fills in the sole completion, Improve your data management with DataToolkits & co..
(⋅) data> help
 Command  Action
 cowsay   Hear what the cow has to say
 help     Display help information on the available commands

(⋅) data> ?cowsay3
 Hear what the cow has to say

 Call with no argument to obtain a fortune.

(⋅) data> cowsay
Are you ready to hear your fortune? [Y/n]: y
/ (1) A sheet of paper is an ink-lined    \
| plane. (2) An inclined plane is a slope |
| up. (3) A slow pup is a lazy dog.       |
|                                         |
| QED: A sheet of paper is a lazy dog.    |
|                                         |
| -- Willard Espy, "An Almanac of Words   |
\ at Play"                                /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||