1. Frank Fischer
  2. evil
  3. Issues
Issue #42 open

C-o across buffers after C-] broken

Anonymous created an issue

If I follow a tag in a TAG file using C-] that directs to another buffer, then pressing C-o does not return to the original buffer: it goes to the top of the current buffer, and pressing C-o again says "Mark popped".

Comments (20)

  1. Vegard Øye

    Evil's jump list is implemented in terms of Emacs' mark ring, which is local to the buffer. Thus, C-o (which corresponds to the Emacs command C-u C-<SPC>) cannot switch from one buffer to another.

    Emacs also has a global mark ring (accessed with C-x C-<SPC> (pop-global-mark)), which might be more useful here. However, there are some minor differences from the local mark ring that make reimplementing C-o/C-i tricky:

    • The behaviour of push-mark w.r.t. global-mark-ring depends on whether the last global mark pushed was in the current buffer or not; if yes, only a local mark is pushed, which is without any use for jumping between files/buffers.
    • Unlike, e.g., registers, Emacs markers are useful only as long as the buffer they point to exists; for Vim-like jumps, it's completely possible to jump to a file which is not visited any more and have the file reopened.

    So a custom mark ring may be needed instead. This would work well with movement commands defined with Evil's macros, but not with standard Emacs commands which save the position with push-mark instead.

  2. Bailey Ling

    i've been able to replicate this behavior using the jumpc package.

    (define-key evil-normal-state-map (kbd "C-o") 'jumpc-jump-backward)
    (define-key evil-normal-state-map (kbd "C-i") 'jumpc-jump-forward)

    and an added bonus, the package writes to ~/.viminfo so you can switch between emacs and vim.

    edit: unfortunately jumpc does not save as many jumps as vim does, so it's still not the same experience as in vim.

  3. Bailey Ling

    i did a first-pass implementation here: https://github.com/bling/evil-jumper

    it serves my majority use case of the jump list, which is typically jumping to a definition in another file, and then jumping back to the original location. i've been using it for a couple days now and it's working great.

    i think this is a killer feature of vim that should be provided out of the box in evil-mode, so please let me know if there's anything in the implementation itself that should be changed to make this mergeable upstream. if it's all good, i can update the integration points and initiate a pull request. thanks.

  4. Bailey Ling

    i can definitely look into that, but there's a couple questions i have.

    1. do you want this to replace the existing implementation altogether or provide an option to choose?
    2. evil-jumper allows the user to specify a path to a file where it will persist the jumps. there are no other evil settings that save files, so some guidance here would be helpful. it is currently nil by default, but if you think it should persist by default then perhaps we can use a sensible name like ~/.evil-jumps.
    3. as far as persisting goes, i have an option to autosave the jumps every X seconds to avoid a crashing emacs from losing data. this feature probably doesn't make sense to be part of the mainline. if you agree as well, i will exclude this as part of the patch.


  5. Nicolas Wu

    One missing feature I just noticed with evil-jumper before I'd call it a complete substitute is that the jumps are not per window... I don't think it should be merged in until this is included.

  6. Bailey Ling

    the only complication there is that emacs doesn't have window-local variables, so adding support may or may not be easy.

    also, ~/.viminfo only stores a single jump list, and it's not per-window, so vim itself has some odd behavior if we want to replicate it exactly.

  7. Frank Fischer repo owner

    I have no strong opinion about jump lists, because I do not use them myself. So I completely rely on the judgement of others (of those who use them like you ;)). Regarding your questions:

    1. it could replace the default behaviour -- but what are the differences? Is the new behaviour closer to Vim's? What would not work anymore as expected (maybe, which test cases would fail?)?

    2. I do not know if there are some guidelines where Emacs packages should store configuration information nowadays. Maybe to some file below '~/.emacs.d' or something below '~/.config'? I do not know if the Emacs manual says something about this.

    3. Maybe one could hook into auto-save-hook or so and save the jump-list only if it has changed? But an option to deactivate this auto save behaviour would definitely be a good idea (and it could be deactivated by default -- no reason to remove it completely IMHO).

    Am 01.09.2014 um 16:57 schrieb Bailey Ling:

  8. Bailey Ling

    Nicolas Wu implementing it as per-buffer will raise other problems, and would result in an implementation that is different from vim, as opposed to an implementation missing a feature.

    Frank Fischer specifically, evil's implementation currently piggybacks on the mark ring. however, mark rings are buffer-local, so if you wanted to jump back to a previous file you would have to use the global mark ring (a separate key binding). evil-jumper stores its own list and doesn't use the built-in mark ring(s), which allows you to C-o/C-i across all buffers you have open (and if you killed a buffer it'll resurrect if necessary, just like vim).

  9. Nicolas Wu

    Bailey Ling: The implementation would be different in both cases. I'd argue that per-buffer is closer to vim since It would be the same behaviour in vim where each buffer is used in at most one window. I do take your point that it might raise other problems though.

  10. Bailey Ling

    Nicolas Wu so i took a first pass at implementing jump lists on a per-window basis, and it's available on a separate branch here. if you can try it out and let me know of any problems it'd be greatly appreciated. i'm going to test it a couple days before i merge it to master and push to MELPA, but otherwise if it's stable then i'll start making the necessary changes to make it mergeable to evil core. thanks.

  11. Robert Melton

    A common idiom in vim is to jump into another other file with a tag jump or definition helper, read the function, then hop back to right where you were, this is deep muscle memory for many vimmers (myself included) and fundamental part of workflows. If the goal of evil is the emulate workflows that vimmers expect, this is IMHO, a critical piece.

  12. Nicolas Wu

    Bailey Ling I started trying to test this, and my first instinct was to use the :jumps command, but of course, this isn't vim so that's not implemented! [feature request ;-)]

    In any case, I don't think it's behaving like I expect it to: I'm using two windows using :vsplit, and it seems like the jump list on a buffer shared in those windows is somehow shared: each buffer should have its own distinct jump list, which is initially forked from the window you're working on. the lists are then completely separate.

  13. Bailey Ling

    Nicolas Wu if you could give me a sample test case that'd be greatly appreciated.

    the "test" that i've been using is this:

    1. open some elisp file.
    2. search for setq, n, n, n, n, n, n.
    3. : vsplit to open new split on the right
    4. C-w h to go back to the left split, C-o, C-o, C-o, C-o to jump back a couple setqs.
    5. C-w l to go the right
    6. confirm that the cursor location is at the last n. C-o back one to verify it only moves back one line.
    7. C-w h back to the left and confirm the cursor position there is maintained and independent.

    P.S. someone's already requested helm integration :S

  14. Log in to comment