diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 314b73a951d61..f2ae35b73b2f0 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -94,10 +94,10 @@ options(s::PromptState) = end function setmark(s::MIState, guess_region_active::Bool=true) - was_active = is_region_active(s) - guess_region_active && activate_region(s, s.key_repeats > 0 ? :mark : :off) + refresh = set_action!(s, :setmark) + s.current_action === :setmark && s.key_repeats > 0 && activate_region(s, :mark) mark(buffer(s)) - was_active && refresh_line(s) + refresh && refresh_line(s) nothing end @@ -239,30 +239,35 @@ function preserve_active(command::Symbol) command ∈ [:edit_indent, :edit_transpose_lines_down!, :edit_transpose_lines_up!] end +# returns whether the "active region" status changed visibly, +# i.e. whether there should be a visual refresh function set_action!(s::MIState, command::Symbol) # if a command is already running, don't update the current_action field, # as the caller is used as a helper function - s.current_action === :unknown || return + s.current_action === :unknown || return false + + active = region_active(s) + + ## record current action + s.current_action = command ## handle activeness of the region - is_shift_move(cmd) = startswith(String(cmd), "shift_") - if is_shift_move(command) - if region_active(s) !== :shift - setmark(s, false) + if startswith(String(command), "shift_") # shift-move command + if active !== :shift + setmark(s) # s.current_action must already have been set activate_region(s, :shift) # NOTE: if the region was already active from a non-shift # move (e.g. ^Space^Space), the region is visibly changed + return active !== :off # active status is reset end elseif !(preserve_active(command) || command_group(command) === :movement && region_active(s) === :mark) # if we move after a shift-move, the region is de-activated # (e.g. like emacs behavior) deactivate_region(s) + return active !== :off end - - ## record current action - s.current_action = command - nothing + false end set_action!(s, command::Symbol) = nothing diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 8046ba03f99f7..6f34f31d2dc72 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -1059,3 +1059,21 @@ fake_repl() do stdin_write, stdout_read, repl wait(repltask) @test istaskdone(repltask) end + +fake_repl() do stdin_write, stdout_read, repl + repltask = @async begin + REPL.run_repl(repl) + end + write(stdin_write, "anything\x15\x19\x19") # ^u^y^y : kill line backwards + 2 yanks + s1 = readuntil(stdout_read, "anything") # typed + s2 = readuntil(stdout_read, "anything") # yanked (first ^y) + s3 = readuntil(stdout_read, "anything") # previous yanked refreshed (from second ^y) + s4 = readuntil(stdout_read, "anything", keep=true) # last yanked + # necessary to read at least some part of the buffer, + # for the "region_active" to have time to be updated + + @test LineEdit.state(repl.mistate).region_active == :off + @test s4 == "anything" # no control characters between the last two occurences of "anything" + write(stdin_write, "\x15\x04") + Base.wait(repltask) +end