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>
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
.
DataToolkitBase.REPL_CMDS
— ConstantThe set of commands available directly in the Data REPL.
DataToolkitBase.ReplCmd
— TypeA 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 toString(name)
).description
, a short overview of the functionality as astring
ordisplay
able 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 anAbstractString
(for example, 'cmd arg1 arg2' will call the execute function with "arg1 arg2").
Constructors
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)
Examples
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)))))
Methods
help(::ReplCmd) # -> print detailed help
allcompletions(::ReplCmd) # -> list all candidates
completions(::ReplCmd, sofar::AbstractString) # -> list relevant candidates
Completion
As hinted by the ReplCmd
docstring, completions can be implemented by implementing completions(::ReplCmd{:CMD_ID}, sofar::AbstractString)
or allcompletions
.
DataToolkitBase.completions
— Functioncompletions(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.
DataToolkitBase.allcompletions
— Functionallcompletions(r::ReplCmd)
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.
DataToolkitBase.prompt
— Functionprompt(question::AbstractString, default::AbstractString="",
allowempty::Bool=false, cleardefault::Bool=true,
multiline::Bool=false)
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
Example
julia> prompt("What colour is the sky? ")
What colour is the sky? Blue
"Blue"
DataToolkitBase.prompt_char
— Functionprompt_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.
DataToolkitBase.confirm_yn
— Functionconfirm_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.
Example
julia> confirm_yn("Do you like chocolate?", true)
Do you like chocolate? [Y/n]: y
true
DataToolkitBase.peelword
— Functionpeelword(input::AbstractString)
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)
.
Example
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))
else
println(read(`cowsay $input`, String))
end
end
push!(REPL_CMDS, ReplCmd(:cowsay3,
"Hear what the cow has to say
\n Call with no argument to obtain a fortune.",
cowsay_repl))
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 indata> help
- running
cowsay
with no arguments results in a Y/n prompt to show a fortune - pressing
TAB
aftercowsay
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 |
|| ||