Skip to content
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

Preserve register values when merging new ones #3354

Open
Screwtapello opened this issue Feb 9, 2020 · 2 comments
Open

Preserve register values when merging new ones #3354

Screwtapello opened this issue Feb 9, 2020 · 2 comments

Comments

@Screwtapello
Copy link
Contributor

@Screwtapello Screwtapello commented Feb 9, 2020

Steps

  1. Start Kakoune without any plugins:

     kak -n
    
  2. Create 100 Kakoune-quoted commands:

     %|printf "'echo %d' " $(seq 100)<ret>
    
  3. Yank those commands:

     %y
    
  4. Merge them into the command history register:

     :reg colon %reg{dquote}<ret>
    
  5. Add a new command to the command history register:

     :echo foo<ret>
    
  6. If you type : to open the prompt and use the up and down arrows to browse through the history, you'll see that echo foo is the most recent command, and echo 1 has been discarded, because Kakoune only stores the last 100 commands

  7. Merge the previous commands into the command history register again:

     :eval reg colon %reg{dquote}<ret>
    
  8. Type : to open the prompt, and use the up and down arrows to browse through the history.

Outcome

The new command echo foo has been forgotten, and only the old echo 1 .. echo 100 commands are present.

Expected

Commands from the local history (echo foo) should have survived, and commands from the remote history (echo 1, echo 2) etc. discarded to make room.

Notes

I recently hit this problem with my kakoune-state-save plugin: after using it for a while, it would load my command history but not update it. Eventually I figured out that when I quit Kakoune, the following sequence of events would take place:

  • My KakEnd hook called state-save-reg-sync colon
  • state-save-reg-sync colon called state-save-reg-load colon to merge any other commands that might have been written out by other Kakoune sessions that ended after this one started
  • But the colon.register file on disk already contained 100 items! So it would completely replace the current session's command history, instead of merging with it.
  • state-save-reg-sync colon called state-save-reg-save colon to write the "merged" history back out to disk

One alternative would be for me to give up on merging values from other sessions - always load at startup, always save at shutdown, and any changes made between the two get clobbered. Unfortunate, but a lot of other tools work the same way, so it might not be the worst thing.

Another alternative would be, instead of the :reg command sometimes merging and sometimes clobbering depending on the register, have it always clobber by default and teach it some new options:

  • -merge-over: the new history will consist of items common between the old and new lists, items unique to the old list, and items unique to the new list, from oldest to newest. If the resulting number of items exceeds the limit, the oldest items will be dropped.
  • -merge-under: the new history will consist of items common between the old and new lists, items unique to the new list, and items unique to the old list, from oldest to newest. If the resulting number of items exceeds the limit, the oldest items will be dropped.

We don't need a special mode for appending to history, as :reg colon blah does today, since you can just do:

reg colon %reg{colon} blah
@lenormf

This comment has been minimized.

Copy link
Contributor

@lenormf lenormf commented Feb 9, 2020

I couldn't get your reproducer to run (possibly a a-s missing, and a different implementation of printf), here's what I used:

%d 100o <c-r># b
:reg colon %reg{.}

As for your problem, as I understand you're requesting to have a "merge" flag on :reg. But the steps you gave to illustrate the problem lead to the expected outcome, don't they?

  1. Insert 100 (i.e. size_limit) commands in the command history
  2. Execute a command
  3. Re-Insert the same 100 commands

The expected outcome is to have the 100 commands that were inserted first in the command history, right?

@Screwtapello

This comment has been minimized.

Copy link
Contributor Author

@Screwtapello Screwtapello commented Feb 14, 2020

Looks like I omitted an eval from my reproducer while I was trying to simplify it; I've edited it back in. Regardless, your version does basically the same thing.

As for "expected outcome", the way these registers were described to me was that new values would be "merged" with existing values, which I assumed was like a Git merge - you have a common history, then branches with different additions, and when you merge you get the union of all the branches. And in fact Kakoune does currently behave like that - as long as there are less than 100 unique history items in total.

I couldn't honestly say the current behaviour is buggy - it has some sensibly-chosen invariants like "never more than 100 items of history" and "the most recently added item is always at the end", and a sensible implementation that ensures those invariants are always upheld. However, part of the reason why history registers were introduced was so that they could be saved and restored externally, and the current implementation makes that use-case difficult.

Maybe the answer is to allow an unlimited number of history items, or to impose the limit after the merge operation instead of during, or some other, wilder approach the one I outlined in the OP. My point is, Kakoune would be more useful if its implementation were more flexible in this specific way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.