diff --git a/stdlib/REPL/docs/src/index.md b/stdlib/REPL/docs/src/index.md index 323d0f13fbbe7..eac6f850fb81d 100644 --- a/stdlib/REPL/docs/src/index.md +++ b/stdlib/REPL/docs/src/index.md @@ -174,6 +174,7 @@ to do so), or pressing Esc and then the key. | `^Q` | Write a number in REPL and press `^Q` to open editor at corresponding stackframe or method | | `meta-Left Arrow` | indent the current line on the left | | `meta-Right Arrow` | indent the current line on the right | +| `meta-.` | insert last word from previous history entry | ### Customizing keybindings diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 0a71488859819..d25747eb89d62 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -1942,6 +1942,25 @@ function move_line_end(buf::IOBuffer) nothing end +edit_insert_last_word(s::MIState) = + edit_insert(s, get_last_word(IOBuffer(mode(s).hist.history[end]))) + +function get_last_word(buf::IOBuffer) + move_line_end(buf) + char_move_word_left(buf) + posbeg = position(buf) + char_move_word_right(buf) + posend = position(buf) + buf = take!(buf) + word = String(buf[posbeg+1:posend]) + rest = String(buf[posend+1:end]) + lp, rp, lb, rb = count.(.==(('(', ')', '[', ']')), rest) + special = any(in.(('\'', '"', '`'), rest)) + !special && lp == rp && lb == rb ? + word *= rest : + word +end + function commit_line(s) cancel_beep(s) move_input_end(s) @@ -2080,6 +2099,7 @@ AnyDict( "\eOc" => "\ef", # Meta Enter "\e\r" => (s,o...)->edit_insert_newline(s), + "\e." => (s,o...)->edit_insert_last_word(s), "\e\n" => "\e\r", "^_" => (s,o...)->edit_undo!(s), "\e_" => (s,o...)->edit_redo!(s), diff --git a/stdlib/REPL/test/lineedit.jl b/stdlib/REPL/test/lineedit.jl index 5125b11d97a8e..abd0610b0db03 100644 --- a/stdlib/REPL/test/lineedit.jl +++ b/stdlib/REPL/test/lineedit.jl @@ -878,5 +878,20 @@ end buf.mark = 0 seek(buf, 1) @test transform!(transpose_lines_down_reg!, buf) == ("l2\nl3\nl1", 4, 3) +end +@testset "edit_insert_last_word" begin + get_last_word(str::String) = LineEdit.get_last_word(IOBuffer(str)) + @test get_last_word("1+2") == "2" + @test get_last_word("1+23") == "23" + @test get_last_word("1+2") == "2" + @test get_last_word(""" "a" * "b" """) == "b" + @test get_last_word(""" "a" * 'b' """) == "b" + @test get_last_word(""" "a" * `b` """) == "b" + @test get_last_word("g()") == "g()" + @test get_last_word("g(1, 2)") == "2" + @test get_last_word("g(1, f())") == "f" + @test get_last_word("a[1]") == "1" + @test get_last_word("a[b[]]") == "b" + @test get_last_word("a[]") == "a[]" end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 5da586b4586aa..56e9b03b97d43 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -415,6 +415,11 @@ for prompt = ["TestĪ ", () -> randstring(rand(1:10))] s = LineEdit.init_state(repl.t, repl.interface) LineEdit.edit_insert(s, "wip") + # LineEdit functions related to history + LineEdit.edit_insert_last_word(s) + @test buffercontents(LineEdit.buffer(s)) == "wip2" + LineEdit.edit_backspace(s) # remove the "2" + # Test that navigating history skips invalid modes # (in both directions) LineEdit.history_prev(s, hp)