Navigation Menu

Skip to content

Commit

Permalink
compatibility with OhMyREPL + code clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
chakravala committed Sep 17, 2017
1 parent 8968bfb commit 58b5afd
Show file tree
Hide file tree
Showing 5 changed files with 426 additions and 237 deletions.
2 changes: 2 additions & 0 deletions .codecov.yml
@@ -1 +1,3 @@
comment: false
ignore:
- "src/repl.jl" # not testable
168 changes: 101 additions & 67 deletions src/Reduce.jl
Expand Up @@ -8,42 +8,50 @@ using Compat; import Compat.String
include(joinpath(dirname(@__FILE__),"../deps/svn.jl"))

immutable PSL <: Base.AbstractPipe
input::Pipe; output::Pipe; process::Base.Process
function PSL()
if !is_windows()
try
# Setup pipes and reduce process
input = Pipe(); output = Pipe()
process = spawn(`$rpsl`, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out); close(output.in)
return new(input, output, process)
catch
# Setup pipes and reduce process
input = Pipe(); output = Pipe()
if is_linux()
cmd = `$(joinpath(dirname(@__FILE__),"..","deps","usr","bin"))/$rpsl`
elseif is_apple()
cmd = `$(joinpath(dirname(@__FILE__),"..","deps","psl"))/$rpsl`
input::Pipe
output::Pipe
process::Base.Process
function PSL()
if !is_windows()
try
# Setup pipes and reduce process
input = Pipe()
output = Pipe()
process = spawn(`$rpsl`, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out)
close(output.in)
return new(input, output, process)
catch
# Setup pipes and reduce process
input = Pipe()
output = Pipe()
if is_linux()
cmd = `$(joinpath(dirname(@__FILE__),"..","deps","usr","bin"))/$rpsl`
elseif is_apple()
cmd = `$(joinpath(dirname(@__FILE__),"..","deps","psl"))/$rpsl`
else
cmd = `$(joinpath(dirname(@__FILE__),"..",rsvn[ρ],"bin"))/$rpsl`
end
process = spawn(cmd, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out)
close(output.in)
return new(input, output, process)
end
else
cmd = `$(joinpath(dirname(@__FILE__),"..",rsvn[ρ],"bin"))/$rpsl`
# Setup pipes and reduce process
input = Pipe()
output = Pipe()
folder = dirname(@__FILE__)
folder = (contains(folder,"appveyor") ? joinpath(folder,"..","deps","psl") :
joinpath(folder,"..","deps","install","lib","psl"))
cmd = `"$(folder)\psl\bpsl.exe" -td 16000000 -f "$(folder)\red\reduce.img"`
process = spawn(cmd, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out); close(output.in)
return new(input, output, process)
end
process = spawn(cmd, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out); close(output.in)
return new(input, output, process)
end
else
# Setup pipes and reduce process
input = Pipe(); output = Pipe(); folder = dirname(@__FILE__)
folder = (contains(folder,"appveyor") ? joinpath(folder,"..","deps","psl") :
joinpath(folder,"..","deps","install","lib","psl"))
cmd = `"$(folder)\psl\bpsl.exe" -td 16000000 -f "$(folder)\red\reduce.img"`
process = spawn(cmd, (input, output, STDERR))
# Close the unneeded ends of Pipes
close(input.out); close(output.in)
return new(input, output, process)
end
end; end

Base.kill(rs::PSL) = kill(rs.process)
Expand All @@ -53,26 +61,28 @@ clear(rs::PSL) = (write(rs.input,";\n"); readavailable(rs.output))
clears = (()->(c=true; return (tf=c)->(ctf && (c=tf); return c)))()

const EOT = Char(4) # end of transmission character
function Base.write(rs::PSL, input::Compat.String); clears() && clear(rs)
write(rs.input,"$input; symbolic write(string $(Int(EOT)));\n"); end

if VERSION < v"0.5.0" # backwards compatability
function Base.write(rs::PSL, input::UTF8String); clears() && clear(rs)
write(rs.input,"$input; symbolic write(string $(Int(EOT)));\n"); end
function Base.write(rs::PSL, input::ASCIIString); clears() && clear(rs)
write(rs.input,"$input; symbolic write(string $(Int(EOT)));\n"); end

function Base.write(rs::PSL, input::Compat.String)
clears() && clear(rs)
write(rs.input,"$input; symbolic write(string $(Int(EOT)));\n")
end

function ReduceCheck(output) # check for REDUCE errors
contains(output,"***** ") && throw(ReduceError(output)); end
contains(output,"***** ") && throw(ReduceError(output))
end

const SOS = "[0-9]+: " # REDUCE terminal prompt
const RES = Regex("\n($EOT\n$SOS)|(\n$SOS\n$EOT)|(\n$SOS$EOT\n)|($EOT\n)")

function Base.read(rs::PSL) # get result and strip prompts/EOT char
out = String(readuntil(rs.output,EOT))*String(readavailable(rs.output))
is_windows() && (out = replace(out,r"\r",""))
out = replace(replace(out,r"\$\n\n","\n\n"),RES,"")
out = replace(out,Regex(SOS),""); ReduceCheck(out); return out; end
out = String(readuntil(rs.output,EOT))*String(readavailable(rs.output))
is_windows() && (out = replace(out,r"\r",""))
out = replace(replace(out,r"\$\n\n","\n\n"),RES,"")
out = replace(out,Regex(SOS),"")
ReduceCheck(out)
return out
end

readsp(rs::PSL) = split(read(rs),"\n\n\n")

include("rexpr.jl") # load RExpr features
Expand All @@ -87,18 +97,28 @@ show(io::IO, r::RExpr) = print(io,convert(Compat.String,r))
Base.write(rs::PSL,r::RExpr) = write(rs,convert(Compat.String,r))

@compat function show(io::IO, ::MIME"text/plain", r::RExpr)
length(r.str) > 1 && (show(string(r)); return nothing)
write(rs,"on nat"*r*"off nat"); output = join(split(read(rs),"\n")[2:end-1],'\n')
print(io,chomp(replace(output,Regex("\n"*SOS),""))); end
length(r.str) > 1 && (show(string(r)); return nothing)
write(rs,"on nat"*r*"off nat")
output = join(split(read(rs),"\n")[2:end-1],'\n')
print(io,chomp(replace(output,Regex("\n"*SOS),"")))
end

@compat function show(io::IO, ::MIME"text/latex", r::RExpr)
rcall(R"on latex"); write(rs,r); rd = readsp(rs)
rcall(R"off latex"); sp = split(join(rd),"\n\n")
print(io,"\\begin{eqnarray}\n"); ct = 0 # add enumeration
for str sp; ct += 1; length(sp) 1 && print(io,"($ct)\&\\,")
print(io,replace(str,r"(\\begin{displaymath})|(\\end{displaymath})",""))
ct length(sp) && print(io,"\\\\\\\\"); end # new line
print(io,"\n\\end{eqnarray}"); end
rcall(R"on latex")
write(rs,r)
rd = readsp(rs)
rcall(R"off latex")
sp = split(join(rd),"\n\n")
print(io,"\\begin{eqnarray}\n")
ct = 0 # add enumeration
for str sp
ct += 1
length(sp) 1 && print(io,"($ct)\&\\,")
print(io,replace(str,r"(\\begin{displaymath})|(\\end{displaymath})",""))
ct length(sp) && print(io,"\\\\\\\\")
end # new line
print(io,"\n\\end{eqnarray}")
end

include("repl.jl") # load repl features

Expand All @@ -118,15 +138,29 @@ __init__() = (Load(); atexit(() -> kill(rs)))

# Server setup

function Load(); global rs = PSL(); s = quote; #global rs = PSL()
write(rs.input,"off nat;symbolic write(string $(Int(EOT)));\n")
banner = readuntil(rs.output,EOT) |> String; readavailable(rs.output);
is_windows() && (banner = replace(banner,r"\r","")); ReduceCheck(banner)
!(is_windows() && contains(dirname(@__FILE__),"appveyor")) &&
println(split(String(banner),'\n')[end-3]); rcall(R"load_package rlfi;im:=i"); end
if isdefined(Base,:active_repl) && isinteractive(); eval(s); repl_init(Base.active_repl)
else; atreplinit() do repl; eval(s); !isdefined(Main,:OhMyREPL) &&
(repl.interface = Base.REPL.setup_interface(repl));
repl_init(Base.active_repl); print('\n'); end; end; end
function Load()
global rs = PSL()
s = quote; #global rs = PSL()
write(rs.input,"off nat;symbolic write(string $(Int(EOT)));\n")
banner = readuntil(rs.output,EOT) |> String
readavailable(rs.output)
is_windows() && (banner = replace(banner,r"\r",""))
ReduceCheck(banner)
!(is_windows() && contains(dirname(@__FILE__),"appveyor")) &&
println(split(String(banner),'\n')[end-3])
rcall(R"load_package rlfi;im:=i")
end
if isdefined(Base,:active_repl) && isinteractive()
eval(s)
repl_init(Base.active_repl)
else
atreplinit() do repl
eval(s)
!isdefined(Main,:OhMyREPL) &&
(repl.interface = Base.REPL.setup_interface(repl))
repl_init(Base.active_repl); print('\n')
end
end
end

end # module
156 changes: 96 additions & 60 deletions src/repl.jl
Expand Up @@ -11,14 +11,14 @@ ans = nothing
Examine the buffer in the repl to see if the input is complete
"""
function finished(s)
str = Compat.String(LineEdit.buffer(s))
if length(str) == 0
return false
elseif str[end] == ';' || str[end] == '$'
return true
else
return false
end
str = Compat.String(LineEdit.buffer(s))
if length(str) == 0
return false
elseif str[end] == ';' || str[end] == '$'
return true
else
return false
end
end

"""
Expand All @@ -27,69 +27,105 @@ end
Something dark and magic
"""
function respond(repl, main)
(s, buf, ok) -> begin
if !ok; return REPL.transition(s, :abort); end
input = String(take!(buf))
if '%' in input
tail = last(input) # chop the tail
input = subst("$(ans)", "%", input[1:end-1]) # substitute
input = string(input, tail); end # add the tail
if !isempty(strip(input))
try; global ans = RExpr(input[1:end-1]); REPL.reset(repl)
if input[end] == ';'
REPL.print_response(repl, ans, nothing, true, Base.have_color)
else; REPL.print_response(repl, nothing, nothing, true, Base.have_color); end
catch err; REPL.reset(repl)
REPL.print_response(repl, err, catch_backtrace(), true, Base.have_color); end
(s, buf, ok) -> begin
if !ok
return REPL.transition(s, :abort)
end
input = String(take!(buf))
if '%' in input
tail = last(input) # chop the tail
input = subst("$(ans)", "%", input[1:end-1]) # substitute
input = string(input, tail) # add the tail
end
if !isempty(strip(input))
try
global ans = RExpr(input[1:end-1])
REPL.reset(repl)
if input[end] == ';'
REPL.print_response(repl, ans, nothing, true, Base.have_color)
else
REPL.print_response(repl, nothing, nothing, true, Base.have_color)
end
catch err
REPL.reset(repl)
REPL.print_response(repl, err, catch_backtrace(), true, Base.have_color)
end
end
REPL.prepare_next(repl)
REPL.reset_state(s)
s.current_mode.sticky || REPL.transition(s, main)
end
REPL.prepare_next(repl); REPL.reset_state(s)
s.current_mode.sticky || REPL.transition(s, main); end; end
end

"""
ReduceCompletionProvider
Basic completion provider, just latex completions
"""
type ReduceCompletionProvider <: LineEdit.CompletionProvider
r::REPL.LineEditREPL; end
r::REPL.LineEditREPL
end

function LineEdit.complete_line(c::ReduceCompletionProvider, s)
buf = s.input_buffer; partial = Compat.String(buf.data[1:buf.ptr-1])
full = LineEdit.input_string(s) # complete latex
ret, range, should_complete = REPLCompletions.bslash_completions(full, endof(partial))[2]
if length(ret) > 0 && should_complete
return ret, partial[range], true; end
return Compat.String[], 0:-1, false; end
buf = s.input_buffer
partial = Compat.String(buf.data[1:buf.ptr-1])
full = LineEdit.input_string(s) # complete latex
ret, range, should_complete = REPLCompletions.bslash_completions(full, endof(partial))[2]
if length(ret) > 0 && should_complete
return ret, partial[range], true
end
return Compat.String[], 0:-1, false
end

function create_reduce_repl(repl, main)
reduce_mode = LineEdit.Prompt("reduce> ";
prompt_prefix = Base.text_colors[:blue],
prompt_suffix = main.prompt_suffix,
on_enter = finished,
on_done = respond(repl, main),
sticky = true)
hp = main.hist; hp.mode_mapping[:reduce] = reduce_mode
reduce_mode.hist = hp; reduce_mode.complete = ReduceCompletionProvider(repl)
search_prompt, skeymap = LineEdit.setup_search_keymap(hp)
prefix_prompt, prefix_keymap = LineEdit.setup_prefix_keymap(hp, reduce_mode)
mk = REPL.mode_keymap(main)
b = Dict{Any,Any}[
skeymap, mk, prefix_keymap, LineEdit.history_keymap,
LineEdit.default_keymap, LineEdit.escape_defaults]
reduce_mode.keymap_dict = LineEdit.keymap(b); reduce_mode; end
reduce_mode = LineEdit.Prompt("reduce> ";
prompt_prefix = Base.text_colors[:blue],
prompt_suffix = main.prompt_suffix,
on_enter = finished,
on_done = respond(repl, main),
sticky = true)
hp = main.hist
hp.mode_mapping[:reduce] = reduce_mode
reduce_mode.hist = hp
reduce_mode.complete = ReduceCompletionProvider(repl)
search_prompt, skeymap = LineEdit.setup_search_keymap(hp)
prefix_prompt, prefix_keymap = LineEdit.setup_prefix_keymap(hp, reduce_mode)
mk = REPL.mode_keymap(main)
b = Dict{Any,Any}[
skeymap, mk, prefix_keymap, LineEdit.history_keymap,
LineEdit.default_keymap, LineEdit.escape_defaults]
reduce_mode.keymap_dict = LineEdit.keymap(b)
reduce_mode
end

function repl_init(repl)
rirepl = isdefined(repl, :ri) ? repl.ri : repl
main_mode = rirepl.interface.modes[1]
reduce_mode = create_reduce_repl(rirepl, main_mode)
push!(rirepl.interface.modes, reduce_mode)
const reduce_prompt_keymap = Dict{Any,Any}(
'}' => function (s,args...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
buf = copy(LineEdit.buffer(s))
LineEdit.transition(s, reduce_mode) do
LineEdit.state(s, reduce_mode).input_buffer = buf; end
else; LineEdit.edit_insert(s, '}'); end; end)
main_mode.keymap_dict = LineEdit.keymap_merge(
main_mode.keymap_dict, reduce_prompt_keymap);
nothing; end
rirepl = isdefined(repl, :ri) ? repl.ri : repl
main_mode = rirepl.interface.modes[1]
reduce_mode = create_reduce_repl(rirepl, main_mode)
push!(rirepl.interface.modes, reduce_mode)
const reduce_prompt_keymap = Dict{Any,Any}(
'}' => function (s,args...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
buf = copy(LineEdit.buffer(s))
LineEdit.transition(s, reduce_mode) do
LineEdit.state(s, reduce_mode).input_buffer = buf
end
else
if !isdefined(Main,:OhMyREPL)
LineEdit.edit_insert(s, '}')
else
if Main.OhMyREPL.BracketInserter.AUTOMATIC_BRACKET_MATCH[] &&
!eof(LineEdit.buffer(s)) &&
Main.OhMyREPL.BracketInserter.peek(LineEdit.buffer(s)) == '}'
LineEdit.edit_move_right(LineEdit.buffer(s))
else
LineEdit.edit_insert(LineEdit.buffer(s), '}')
end
Main.OhMyREPL.Prompt.rewrite_with_ANSI(s)
end
end
end)
main_mode.keymap_dict = LineEdit.keymap_merge(
main_mode.keymap_dict, reduce_prompt_keymap)
nothing
end

0 comments on commit 58b5afd

Please sign in to comment.