9

I frequently have several buffers open in my Vim session. This means that my jump list stores locations from several buffers. However, frequently when I use the Ctrl+O keyboard shortcut to jump to a previous location, I do not want to leave the buffer and want to jump to previous locations “local” to the current buffer. How do I do this?

For example, assume my jump list looks as follows:

4   10   1 ~/aaa.m
3   20   1 ~/aaa.m
2   12   2 ~/xxx.m
1   15   1 ~/aaa.m

I want to jump to line 15 of file aaa.m the first time I press Ctrl+O. Importantly, the next time I press Ctrl+O, I do not want to jump to file xxx.m. Rather, I want to jump to line 20 of file aaa.m, that is, my previous location within the “current” buffer. The default Vim behaviour, though, is to take me to to line 12 of file xxx.m.

Any ideas on how I can achieve this?

ib.
  • 25,324
  • 10
  • 71
  • 97
vimgm
  • 93
  • 3
  • This might be a better question for superuser, stackoverflow questions(and answers) tend relate directly to coding. superuser.com is run by the same people but focuses on using software. – David Waters Aug 15 '11 at 15:10
  • 4
    @David Waters, no. http://meta.stackexchange.com/q/25925/160504 – sidyll Aug 15 '11 at 15:14
  • 2
    Would using the `changelist` fit your needs? You can use `g;` and `g,` to move back and forth though the change list. – Peter Rincker Aug 15 '11 at 15:14
  • @Peter Rincker, thanks for your response. However, this does not solve the problem as I need to jump to previous cursor positions and **not** just the change positions. This frequently happens when I am searching strings in a code and jump from one function to another, without editing the code. – vimgm Aug 15 '11 at 16:38

2 Answers2

10

Try the following jump-list traversing function. It steps successively from one jump-list location to another (using Ctrl+O or Ctrl+I depending on the values that are supplied to its back and forw arguments), and stops if the current location is in the same buffer as that buffer it has started from. If it is not possible to find a jump-list location that belongs to the current buffer, the function returns to the position in the jump list that was the current one before the function was called.

function! JumpWithinFile(back, forw)
    let [n, i] = [bufnr('%'), 1]
    let p = [n] + getpos('.')[1:]
    sil! exe 'norm!1' . a:forw
    while 1
        let p1 = [bufnr('%')] + getpos('.')[1:]
        if n == p1[0] | break | endif
        if p == p1
            sil! exe 'norm!' . (i-1) . a:back
            break
        endif
        let [p, i] = [p1, i+1]
        sil! exe 'norm!1' . a:forw
    endwhile
endfunction

To use this function as a Ctrl+O/Ctrl+I-replacement locked to the current buffer, create mappings as it is shown below.

nnoremap <silent> <c-k> :call JumpWithinFile("\<c-i>", "\<c-o>")<cr>
nnoremap <silent> <c-j> :call JumpWithinFile("\<c-o>", "\<c-i>")<cr>
ib.
  • 25,324
  • 10
  • 71
  • 97
  • 2
    eeck. that is sick. and crafty. Giving you points for swimming against the stream – sehe Aug 16 '11 at 09:37
  • Thanks for writing that code, really interesting solution. It _almost_ works, with a couple of niggles. Firstly, if a directory is in my jump-list (this could be the case because I browsed a directory to open a file), it opens the netrw browser in the current buffer and then gets stuck there. Secondly, when the function reaches the end of the jump-list, it keeps jumping between the last two locations (when `Ctrl+k` is pressed). Is it possible that it either loops through the jump-list, or just stays at the last location? – vimgm Aug 16 '11 at 11:21
  • @sehe: This feels against the grain for me, too. (And personally I would not try to cut corners of default jump-list behavior.) But it's interesting (and a bit hackish) to try to find out a way solving this problem. – ib. Aug 16 '11 at 12:56
  • @vimgm: Could you please minimize an example of incorrect behavior and describe it a little more detail. At the moment I can't reproduce neither problems. – ib. Aug 16 '11 at 13:03
  • @ib: Sure. If jump-list looks like following: [3 15 2 ~/xxx.m] [2 10 2 ~] [1 15 1 ~/aaa.m] (This could happen if you opened `aaa.m` using the command `:e .` from command line) then pressing `Ctrl-k` twice opens the Netrw directory listing for directory `~`. This is undesirable as I want the buffer to keep displaying file aaa.m. Secondly, if the jump-list is as in my original example above, when cursor gets to line 10, `Ctrl-k` makes it jump to line 20. Pressing `Ctrl-k` again makes it jump to line 10 and so on. I would like it to either remain at line 10 or loop back to line 15. – vimgm Aug 16 '11 at 13:36
  • @vimgm: The problem with seemingly infinite jump loop between two location was caused by a mistake: the line `sil! exe 'norm!' . i . a:back` should be `sil! exe 'norm!' . (i-1) . a:back`. The answer is updated. – ib. Aug 17 '11 at 02:35
  • @vimgm: Trying to reproduce your issue with Netrw I did the following. In shell: `$cd /tmp`, `$rm ~/.viminfo` (to clear jump-list), `$echo -e "test\ntest" >t`; then in Vim: `:e.`, `/^t` `Enter`, `Enter`, `2G`. (The script from the answer was appended to `~/.vimrc`.) Then, `Ctrl`-`K` moves the cursor to the first line and keeps it there while pressing `Ctrl`-`K` again and again. Netrw buffer does not appear. – ib. Aug 17 '11 at 02:38
  • 1
    @ib: OK, this works perfectly now. The infinite loop has stopped. I think the Netrw problem was due to the fact that I use the Tabbar plugin (which helps manage switching between buffers) along with Netrw. I have now disabled Netrw and am using NERDTree instead. Everything works like a charm. (Oh, you probably want to remove the `echo`s from the code above). Thanks for all the help. – vimgm Aug 17 '11 at 09:59
  • @vimgm: It works for me with both Netrw and NERDTree (I prefer the former, by the way). Oh, of course, I should clear the debug output out of the code. Don't mention it, I'm glad that my code helped! – ib. Aug 17 '11 at 11:28
1

Maybe the EnhancedJumps plugin will help.

With this plugin installed, the jump to another buffer is only done if the same jump command is repeated once more immediately afterwards.

ib.
  • 25,324
  • 10
  • 71
  • 97
Deqing
  • 11,990
  • 13
  • 74
  • 113