How to prevent leaving the current buffer when traversing the jump list in Vim?
Asked Answered
P

2

15

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?

Patronage answered 15/8, 2011 at 14:55 Comment(4)
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.Cupriferous
@David Waters, no. meta.stackexchange.com/q/25925/160504Symon
Would using the changelist fit your needs? You can use g; and g, to move back and forth though the change list.Swordsman
@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.Patronage
P
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>
Postdoctoral answered 16/8, 2011 at 7:50 Comment(9)
eeck. that is sick. and crafty. Giving you points for swimming against the streamLyall
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?Patronage
@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.Postdoctoral
@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.Postdoctoral
@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.Patronage
@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.Postdoctoral
@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.Postdoctoral
@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 echos from the code above). Thanks for all the help.Patronage
@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!Postdoctoral
L
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.

Ludwig answered 17/4, 2013 at 5:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.