-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
REPL/LineEdit to support "undo": part of #8447 #9596
Conversation
Thanks! I tested it and works fine. I don't know the LineEdit.jl code very well yet, but the patch looks good to me. |
base/LineEdit.jl
Outdated
@@ -1512,7 +1538,7 @@ end | |||
|
|||
run_interface(::Prompt) = nothing | |||
|
|||
init_state(terminal, prompt::Prompt) = PromptState(terminal, prompt, IOBuffer(), InputAreaState(1, 1), length(prompt.prompt)) | |||
init_state(terminal, prompt::Prompt) = PromptState(terminal, prompt, IOBuffer(), (IOBuffer)[], InputAreaState(1, 1), length(prompt.prompt)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not IOBuffer[]
(w/o parens) ?
Oh, and special +1 for extensive tests. |
7e82a32
to
da54cf6
Compare
Looking forward to the beginning/end-of-history! My plan was to next tackle kill/yank which doesn't seem to work quite right: m-d and friends don't get added to yank ring, yank ring isn't yet a ring, etc. |
307d525
to
cf5dfc8
Compare
Bump. I'm really missing this functionality! |
base/LineEdit.jl
Outdated
@@ -146,16 +148,14 @@ function complete_line(s::PromptState, repeats) | |||
elseif length(completions) == 1 | |||
# Replace word by completion | |||
prev_pos = position(s.input_buffer) | |||
seek(s.input_buffer, prev_pos-sizeof(partial)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why have the calls to seek
been dropped here and elsewhere in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably because edit_replace
already is "undo aware", whereas seek
is not. When I compile without this change, after an undo the cursor is misplaced (e.g. at the beginning of a (prefix) word after undoing a completion).
I rebased locally this branch on master, and for some reason the key-binding "^/" is not valid anymore (compilation fails), I don't know why yet. |
@srp would you consider rebasing this work to get it merged? |
Yes, please – this would be a lovely feature to have. Sorry the PR has languished! |
base/repl/LineEdit.jl
Outdated
@@ -1559,7 +1583,7 @@ end | |||
|
|||
run_interface(::Prompt) = nothing | |||
|
|||
init_state(terminal, prompt::Prompt) = PromptState(terminal, prompt, IOBuffer(), InputAreaState(1, 1), #=indent(spaces)=#strwidth(prompt.prompt)) | |||
init_state(terminal, prompt::Prompt) = PromptState(terminal, prompt, IOBuffer(), IOBuffer[], InputAreaState(1, 1), #=indent(spaces)=#strwidth(prompt.prompt)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this line should probably be wrapped
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
The REPL now supports undo via Ctrl-^ or Ctrl-_. This should very closely minic the behavior of other readline/emacs shells, except it doesn't let the user goto a historical entry (A), edit it, goto a different historical entry (B), return to the first (A) and undo the edits.
@rfourquet,@StefanKarpinski: rebased, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your very nice work! None of my comments are blocking, and can be addressed later if needed.
I will merge in a few days if no-one has objections.
@@ -572,15 +592,18 @@ end | |||
edit_clear(buf::IOBuffer) = truncate(buf, 0) | |||
|
|||
function edit_clear(s::MIState) | |||
push_undo(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you could push_undo
only if the buffer is not empty already? Another possibility could also be to not push a new state in push_undo
when it's equal to the last pushed state?
end | ||
|
||
function edit_yank(s::MIState) | ||
push_undo(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you could push_undo
only if !isempty(s.kill_buffer)
?
edit_insert(buffer(s), s.kill_buffer) | ||
refresh_line(s) | ||
end | ||
|
||
function edit_kill_line(s::MIState) | ||
push_undo(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
push_undo
only if some characters are deleted?
push_undo(s) = nothing | ||
|
||
function pop_undo(s::PromptState) | ||
length(s.undo_buffers) > 0 || return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isempty(s.undo_buffers) && return false
@@ -401,3 +401,96 @@ let | |||
Base.LineEdit.InputAreaState(0,0), "julia> ", indent = 7) | |||
@test s == Base.LineEdit.InputAreaState(3,1) | |||
end | |||
|
|||
# test Undo | |||
let |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use @testset
?
@@ -172,6 +172,7 @@ to do so). | |||
| `^Y` | "Yank" insert the text from the kill buffer | | |||
| `^T` | Transpose the characters about the cursor | | |||
| `^Q` | Write a number in REPL and press `^Q` to open editor at corresponding stackframe or method | | |||
| `^/`, `^_` | Undo | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see you add a key for ^/
, how does it work? (when I tried to rebase last year, I had compilation problems with this key...)
Also, your commit message refers to "Ctrl-^", you should change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^/ isn't a valid control character (eg after subtracting 64 you get a negative number), however it appears that vt102 terminal emulators map it to emit ^_ for convience, see: https://apple.stackexchange.com/a/227286
From the terminals I tested on this is accurate that pressing ctrl-/ causes "^_" to appear in the console.
end | ||
empty_undo(s) = nothing | ||
|
||
function push_undo(s::PromptState) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer the names of the new functions with an ending !
, but it seems to be the style of the file, so better to keep as is for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this one is a good candidate for short-form function syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably all be refactored to have !
. It wasn't clear to me reading through this that it actually modified the PromptState
until I saw the definition. The larger refactoring doesn't have to happen in this PR, but if you're adding a function now, might as well use the standard notation, IMO.
How do I type |
|
Does Ctrl+_ work on a Swedish keyboard? If so, you might have to stick with that. |
|
Sounds the same as an english keyboard, i have to hit |
@rfourquet I plan on pushing an update addressing some of your comments, but in the process noticed that undo doesn't work right (any more?) with bracketed insert. I'm trying to fix that, but so far it's not entirely straight forward. |
@srp, I rebased your branch and tried to fix undo with the bracketed paste mode, would you mind checking out this branch (just do |
Bump - I have few features in the pipeline which will increase the work to resolve conflicts here if we don't merge this first... |
I rebased again and updated the branch "srp/repl-undo" that I linked to above. I plan to merge by tomorrow. But I cannot update the PR directly, and I'm afraid that if I merge it on the command line, github won't recognize this PR has been merged (it happened to me already), someone would have a hint as to how to do it properly? |
Thanks again @srp ! |
The REPL now supports undo via Ctrl-^ or Ctrl-_.
This should very closely minic the behavior of other readline/emacs
shells, except it doesn't let the user goto a historical entry (A),
edit it, goto a different historical entry (B), return to the first
(A) and undo the edits.
This change is