hi. i’d like to interact with the user of my julia program with the input being more “command line” than “function call” like, but take advantage of the command line editing, history, etc., the REPL offers. so, the user would type things like
modify r1.2
rather than
modify("r1.2")
Pkg
and Debugger
, at least, seem to offer this sort of interface (i don’t know how general their access is). and, i suspect if i had the user type @modify
i could probably solve my problem.
my question is, is there a not-too-difficult, more-or-less-documented way of doing this?
thanks!
I recommend writing a macro, though it is unlikely you will be able to get the .
in r1.2
to work well. See
julia> t = :(@modify r1.2)
:(#= REPL[4]:1 =# @modify r1 0.2)
It gets parsed as r1
and a number.
You can use REPLMaker.jl to make a custom REPL. Once you write a macro that should be easy to implement.
1 Like
@pdeffebach thanks. i’ll take a look at REPLMaker.jl.
@pdeffebach again thanks. using ReplMaker.jl
and Tokenize.jl
, it seems i can implement a nice (albeit geeky, as planned) UI.
using Tokenize
@enum State skipping accumulating
"""
vecize(str::String)
split a string into components, returning them in a vector. similar
to split, but we obey embedded quotes, returning as singletons in the
vector their strings (without the quotes).
"""
function vecize(str::String)
# shortcut from
# https://github.com/JuliaLang/Tokenize.jl/blob/master/test/lexer.jl
local T = Tokenize.Tokens
local result = []
# so, " r1.2 " will be WHITESPACE IDENTIFIER FLOAT WHITESPACE, and
# " r1.l2 " will be WHITESPACE IDENTIFIER OP(.) IDENTIFIER WHITESPACE
# so, need to concatentate things between WHITESPACE (and/or
# ENDMARKER). so, need to do a small amount of yacc'ing.
local terminators = [T.WHITESPACE T.ENDMARKER]
local state::State = skipping
local accumulated::String = "" # position of first non-white-space in current
local tokened = collect(Tokenize.tokenize(str))
for tok in tokened
# make sure we're all on one line
@assert T.startpos(tok)[1] == 1 "more than one line: $(str)"
@assert T.endpos(tok)[1] == 1 "more than one line: $(str)"
local startpos = T.startpos(tok)[2]
local endpos = T.endpos(tok)[2]
# '(' to allow the line to wrap
# http://julia-programming-language.2336112.n4.nabble.com/Multiple-lines-statement-tp8640p20795.html
@assert T.kind(tok) != T.ERROR (
"invalid input position $(T.startpos(tok)[2]): $(T.untokenize(tok))")
if T.kind(tok) in terminators
if state == accumulating
# done with a run
result = vcat(result, [accumulated])
state = skipping
end
else # by modus pons, this must be something we want
if state == skipping
# first non-blank
state = accumulating
accumulated = ""
end
local content = T.untokenize(tok)
if T.kind(tok) == T.STRING
# get rid of quotes
content = content[2:(end-1)]
end
accumulated *= content
end
end
result
end
# https://github.com/MasonProtter/ReplMaker.jl
using ReplMaker
function parse_to_expr(s)
quote $s end
end
initrepl(vecize,
prompt_text="Expr> ",
prompt_color = :blue,
start_key=')',
mode_name="Expr_mode")
cheers.