From b16afaf79cbe934c7518c2fbf10fb18de0932834 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 4 Nov 2019 12:16:27 +0100 Subject: [PATCH] REPL: allow editing current input in editor (via Meta-e) --- stdlib/REPL/src/LineEdit.jl | 56 +++++++++++++++++++++++++++++++++++++ stdlib/REPL/src/REPL.jl | 11 ++------ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 89f57383d5e48..8d650815f31d6 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -12,6 +12,8 @@ import ..Terminals: raw!, width, height, cmove, getX, import Base: ensureroom, show, AnyDict, position using Base: something +using InteractiveUtils: InteractiveUtils + abstract type TextInterface end # see interface immediately below abstract type ModeState end # see interface below abstract type HistoryProvider end @@ -1295,6 +1297,59 @@ _edit_indent(buf::IOBuffer, b::Int, num::Int) = num >= 0 ? edit_splice!(buf, b => b, ' '^num, rigid_mark=false) : edit_splice!(buf, b => (b - num)) +function mode_idx(hist #=::REPLHistoryProvider =#, mode::TextInterface) + c = :julia + for (k,v) in hist.mode_mapping + isequal(v, mode) && (c = k) + end + return c +end + +function guess_current_mode_name(s) + try + mode_idx(s.current_mode.hist, s.current_mode) + catch + nothing + end +end + +# edit current input in editor +function edit_input(s) + mode_name = guess_current_mode_name(s) + filename = tempname() + if mode_name == :julia + filename *= ".jl" + elseif mode_name == :shell + filename *= ".sh" + end + buf = buffer(s) + data = buf.data + pos = position(buf) + size0 = buf.size + resize!(data, buf.size) # to not write garbage into filename + line = 1 + count(==(_newline), view(data, 1:pos)) + ct0 = open(filename, "w") do io + write(io, data) + ctime(io) + end + InteractiveUtils.edit(filename, line) + n, ct = open(filename) do io + readbytes!(io, empty!(buf.data), typemax(Int)), + ctime(io) + end + rm(filename) + @assert n == length(buf.data) + buf.size = n + buf.ptr = n+1 + if ct0 != ct # something was changed, run the input + commit_line(s) + :done + else # no change, the edit session probably unsuccessful + @assert n == size0 + seek(buf, pos) # restore state from before edit + refresh_line(s) + end +end history_prev(::EmptyHistoryProvider) = ("", false) history_next(::EmptyHistoryProvider) = ("", false) @@ -2337,6 +2392,7 @@ AnyDict( "\eu" => (s::MIState,o...)->edit_upper_case(s), "\el" => (s::MIState,o...)->edit_lower_case(s), "\ec" => (s::MIState,o...)->edit_title_case(s), + "\ee" => (s::MIState,o...) -> edit_input(s), ) const history_keymap = AnyDict( diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index bf3345f158168..5ff5e70e588ba 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -59,7 +59,8 @@ import ..LineEdit: terminal, MIState, PromptState, - TextInterface + TextInterface, + mode_idx include("REPLCompletions.jl") using .REPLCompletions @@ -601,14 +602,6 @@ function hist_from_file(hp::REPLHistoryProvider, path::String) return hp end -function mode_idx(hist::REPLHistoryProvider, mode::TextInterface) - c = :julia - for (k,v) in hist.mode_mapping - isequal(v, mode) && (c = k) - end - return c -end - function add_history(hist::REPLHistoryProvider, s::PromptState) str = rstrip(String(take!(copy(s.input_buffer)))) isempty(strip(str)) && return