Skip to content

Commit

Permalink
REPL: fix yank-twice activates region
Browse files Browse the repository at this point in the history
Yanking twice was fooling `setmark` into believing
that `^Space`, the keybinding for `setmark`, had
been pressed twice, leading to activating the region.
So let's make `setmark` behave as a "command" (and
activate the region) only when called directly by
the user, otherwise treat it as a low-level function.
  • Loading branch information
rfourquet committed Nov 16, 2019
1 parent b29d951 commit da54646
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 12 deletions.
29 changes: 17 additions & 12 deletions stdlib/REPL/src/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions stdlib/REPL/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit da54646

Please sign in to comment.