kakoune
kakoune copied to clipboard
Undo selection change
Hi,
It often happens to me that I carefully craft a selection with multiple cursors, ready to make changes elegantly, only to completely mess it up by pressing a wrong key (by merging the cursors for example). Being able to undo the last selection change (even if only until the previous buffer change) would make this much less painful.
I think it's a bit different, my issue is more of a feature request regarding selection changes within the same state of the buffer, and not really related to the current undo feature.
This happens to me all the times. Do you get all your multiple selections perfectly in your workflow?
@occivink The relevant part is:
I am not sure if we can do much better without saving selections in the undo data, which might be a bit coslty memory wise.
The feature you want would force the editor to save selection modifications, and saving only the last one wouldn't be very consistent, so that's that.
The feature you want would force the editor to save selection modifications, and saving only the last one wouldn't be very consistent, so that's that.
One generally needs to undo selections only when multiple selections are used, what about saving the previous selections as soon as there's more than one selection, while we save only the last one when there is only one?
Tangentially, I think that an hypothetic "undo selection" should be associated to a different command/key than u
.
hook global NormalKey .* %{ %sh{
selection_count=$(echo $kak_selections_desc | awk -F : '{ print NF }')
if test $selection_count -gt 1; then
echo exec '<c-s>'
fi
}}
That actually works nicely, but it's a shame that you kind of lose the jump-list functionality.
Maybe jump list could benefit from registers.
Sublime Text has this feature, and I use it. It does save every cursor and selection modification (coalescing multiple character moves into a single undo item and such), and it offers two undo commands: "undo" (on a mac, cmd+z) and "soft undo" (cmd+u). "Soft undo" undoes everything -- cursor moves or selection changes or modifications -- where "undo" continually undoes everything until it reaches the first modification. I use it for these things, in order of frequency:
- I hit cmd-d too many times and selected one too many words (this seems less compelling in Kakoune given range-refinement)
- I jumped somewhere else in the file, and I want to return my cursor to where it was (an after-the-fact mark, like
``
) - I flubbed a multiselect (though after six years with Sublime, I have gotten pretty careful)
Can we put this under a feature request badge or so? It's an oft-asked feature here and on IRC. I'd be happy to use my computer's memory to store millions of cursors from the past :)
Yeah, I think I will implement that, because it seems pretty useful, and I realized we only need to store selection changes from the last buffer change (they are not relevant before that). What is still missing is a nice keybinding for it.
Yeah, I think I will implement that, because it seems pretty useful, and I realized we only need to store selection changes from the last buffer change (they are not relevant before that). What is still missing is a nice keybinding for it.
we only need to store selection changes from the last buffer change (they are not relevant before that)
What about the undo-tree, aren't all changes relevant to allow going back/forward in time?
we only need to store selection changes from the last buffer change (they are not relevant before that)
I'm also confused about this: I would like to be able to undo several times and have my cursors restore as they were at that point (and not use today's heuristics).
@danr I think you're confusing two issues, you're thinking of saving cursors position in the undo tree (#1184) , while this issue is about a potential new selection-undo-stack which would let you cycle between cursors position without modifying the state of the buffer.
Vim had this feature (in a limited form) as gv
, restoring last selection. I missed it a lot when using kak.
It's been a while since this has been bumped, and it's absence has been my biggest (still minor) annoyance with using kak.
Suggestion for keybindings: gu (back) and gU (forward), since it's really an undoing of a movement command.
If there aren't any plans to look at this in the near future, I can take a look at it when I get a chance. I'd enjoy another excuse to dive into the source.
For reference:
# Save selections to the [b]ackup register.
hook -group backup-selections global NormalIdle .* %{
set-register b %reg{z}
execute-keys -draft '"zZ'
}
# Add a mapping to easily reach the command.
map -docstring 'Restore selections from the [b]ackup register' global user z '"bz'
Another case for which I want this feature: Using f
or t
and then repeating <a-.>
, it's easy to overshoot the character you meant to stop at and want to back up one. In vim I use ;
and ,
to iterate both forward and backward, but in oak I think I would need a selection undo to pair with <a-.>
.
Note for newbies: https://github.com/mawww/kakoune/issues/898#issuecomment-727516233 restores with ,z
(thanks to map ... global user
). It doesn't seem to be possible to move the mapping to e.g. global view
or global goto
(i.e. gz
or vz
)
Prefix the mapping with <esc>
to go back in normal mode where "bz
can be executed.
(I'm completely new to kakoune and to modal editing, but..)
Wasn't this the entire point of having object-verb grammar? As it is right now, having to start a sentence over in Kakoune seems no different than having to undo and then start over in vi.
from "Why Kakoune":
vi basic grammar is verb followed by object ... That means that errors are not handled well. If you express your object wrongly with a delete verb, the wrong text will get deleted, you will need to undo, and try again.
Kakoune’s grammar is object followed by verb, combined with instantaneous feedback, that means you always see the current object (In Kakoune we call that the selection) before you apply your change, which allows you to correct errors on the go.
As an additional note, wouldn't backspace be an appropriate key for this in normal mode? Thinking of the editing model as "interactive sentence-building," an undo selection would be "delete one command from the sentence (object of the sentence)"
@erinkim4 The point of the object->verb grammar is to interactively build and get visual feedback on your "object" before you have to commit to a "verb".
E.g. in Vim, you have to simply know that 5cw
is the amount of words you want to replace. Only after you typed w
you might realize that you wanted just four.
In Kakoune, you could instead do a conservative 3w
, pause and verify, add one more w
and only then commit with c
. Or you can build an arbitrary sequence of n
and <s-n>
if you want to replace very specific occurrences of a search term while leaving others untouched.
It is true that without undo functionality the "correct errors on the go" part is not always possible, especially for the more complex commands. But some selection changes can already be reverted through an opposite action (e.g. <s-h>
reverts <s-l>
).
I understand that, but just having visual feedback doesn't seem to take full advantage of the potential of object-verb grammar. Having opposite actions for everything seems like an ad-hoc solution, and it won't be possible (or easy) for actions that "increase entropy" (e.g. deselect, collapse anchors). Wouldn't it be better to allow users to modify sentences before executing with a verb?
hook global NormalKey .* %{ %sh{ selection_count=$(echo $kak_selections_desc | awk -F : '{ print NF }') if test $selection_count -gt 1; then echo exec '<c-s>' fi }}
After trying this and working on the issues it has had for me, I've completed a working implementation of undo selection change, generated using nix home-manager: https://gist.github.com/erinkim4/1b02459a988ea3fe2b0ac54a4af95f72
It breaks pretty much all autoinfo normal dialogues, but that's a price I'm willing to pay.
The quoted implementation breaks numbers and all "mode keys" (g
, v
, <a-i>
, <a-p>
, [
, ]
, etc.), so I excluded those with regex. But this made it so that none of those functions would trigger a <c-s>
, so i added a hook for <esc>
in normal mode, and since there were no hooks for keys in prompt, goto, or object mode, I mapped every single one of them to trigger <c-s>
.
At some point in the future I'm going to fork kakoune and integrate selections into the undo tree, since this is a pretty terrible workaround.
Update:
I realized that f
and t
didn't work. Since map
lacks modes for f
, t
, <a-f>
, and <a-t>
, I created user modes for each of them, and mapped every single character to execute <c-s>.
Working on this "solution" seemed to expose a number of problems with hooks and maps.
- There are no hooks for keys entered in
prompt
,goto
, orobject
mode. - There are no hooks or maps for
f
andt
modes. - There are no escape characters for commands.
- Maybe maps could benefit from regex.
note: ModeChange
hooks did not work, as they executed <c-s>
before any selection change happened.
Here's the new kakrc, with 468 lines: https://gist.github.com/oati/94c234778c1e2bced4207865f21dc080
I have an experimental implementation in my undo-selection-change branch. Happy to hear feedback on the UI. I haven't tested it much yet (it's hard to unlearn muscle memory).
Functional implementation here, this is indeed a very useful and intuitive feature. Naturally, Gimp has had it for years. I wonder if there are other features we can steal from image editors
So far in my short testing this is great! However I think the keybindings could be better.
I'd like to make 2 additional proposals for default bindings:
-
<c-h>
backwards and<c-l>
forwards- more idiomatic since
h
is char-back andl
is char-forward in normal mode
- more idiomatic since
-
<c-k>
backwards and<c-l>
forwards- directly under
i
ando
, and somewhat similar to<c-i>
and<c-o>
- side by side home row keys (good if this gets used as much as @krobelus says)
- directly under
<c-l>
is a secret undocumented command to force-redraw the screen (rarely necessary but sometimes useful after scrolling a terminal).
This is from the ncurses influence.