I switch from buffer 1 to buffer 2 and my cursor is at line 100. I use j/k to scroll around and land at line 120. Then I use ctrl-O to switch back to buffer 1, and then ctrl-I to go to buffer 2.
I expect that the cursor should be at line 120, as that is where I left off, but to my annoyance, the cursor is at line 100. How can I get vim to go to line 120?
The commands you are using are working as advertised. The problem is that you don't use the right commands for what you are trying to do.
<C-o> and <C-i> are not related to buffers at all. Their job is to let you move up and down the jump list, no more no less. The fact that they lead you to another buffer is a side effect. Don't rely on side effects: if you don't want to navigate the jump list, don't use them.
If you need to alternate between two buffers, the right command is <C-^> (or <C-6> on some keyboards).
If you need to switch to a specific buffer, use :b <tab> or :ls followed by :bn with n being the number of the desired buffer.
Related
Consider a scenario, when you are editing a C file in vim. & you have used a mix of spaces & tabss. & you need to convert all of them to spaces.
There is a utility, called expand, which performs this task intelligently & it's a preferred way than s/\t/<4 spaces>/g. We can use this command in vim using :%!expand -t4. Typically, I map a function key, say F11 for this.
Similarly, we can use any other command in vim.
The problem is when you run any such operation on entire buffer, the cursor position changes & can be irritating at times.
Hence, the question is, how to perform an operation on entire buffer, without changing cursor position?
The cursor position can be restored by using the latest jump mark:
``
If you also want to maintain the exact window view, use winsaveview() / winrestview().
The anwolib - Yet another vim library has a handy :KeepView command for that:
:KeepView %!expand -t4
For such a case, we can use marks (e.g. mA). The mapping would be:
:nmap <F11> mZ:%!expand -t4<CR>`Z
However, there is still a catch. The screen scroll position may change, when operating on entire buffer.
This can be handled by using 2 marks as below:
:nmap <F11> mZHmY:%!expand -t4<CR>'Yzt`Z
Explanation:
Mark current position. (mZ)
Go to top of screen. (H)
Mark this line. (mY)
Run your filter. (:%!expand -t4)
Go to line Y. ('Y)
Make it top of screen. (zt)
Go to your mark. (`Z)
Now, when you press the mapped key, F11, the filter runs on the buffer & the cursor remains at its proper location.
you can just:
:your expand cmd|norm! ``
you can map it to <F11> if you like. but better use nnoremap
I just saw you mentioned in your question:
Similarly, we can use any other command in vim
If you want to do that, the reliable solution would be wrap the "any other command" in a function, and before/after the main logic, save/restore the cursor position. Because "any other command" could change the (back tick) mark, even the marks you defined.
I have modified the IMAP function from vim-latex, so that an undo is possible, by changing the final return line of LookupCharacter to
return a:char . "^Gu\<bs>" . bs . IMAP_PutTextWithMovement(rhs, phs, phe)
Now to do the undo directly from insert mode, I have this mapping in my .vimrc:
imap <Undo> <Esc>ui
I use the Neo2 keyboard layout, so there's an undo key on the 4th layer.
Now this works fairly well, but the problem is that when I use it at the end of a line, the cursor is placed before the last character. To test it without vim-latex, you could do
:imap a a^Gu\<bs>test
type 'b' in the middle and at the end of a line and then execute the undo, by shortcut or by manually pressing <Esc>ui.
So is there a way to make vim jump back to the correct cursor position?
I have seen an entry in wikia which gives an idea, but I don't know how to achieve it with the imap mapping.
The cursor move is due to the indiscriminate use of i at the end of your mapping. Typically, one temporarily executes a normal mode command via
imap <Undo> <C-\><C-o>u
But in your case, as the undo modifies the buffer, this may not work under all circumstances.
Is there a key-combination that behaves as though I'd press ctrl-E followed by a j, that is the text scrolls up a line but the cursor keeps where it is, relativ to the screen.
I am aware that I could achieve what I want with a :map but before I do I thought I'd rather want to know if there is already some "built-in" functionality
Yes, use CTRL-D with a count of 1 (not that that saves you anything, really).
The CTRL-D command does the same as CTRL-E, but also moves the cursor down the same number of lines
There is the z command
z. Redraw, line [count] at center of window (default
cursor line). Put cursor at first non-blank in the
line.
zz Like "z.", but leave the cursor in the same column.
Careful: If caps-lock is on, this commands becomes
"ZZ": write buffer and exit! {not in Vi}
These mappings makes it possible to scroll up and down one line with focus on center line (hard to describe so that it sound correct, try it instead)
"scroll with line in center
map <C-Up> <ESC>0kzz
map <C-Down> <ESC>0jzz
Is it possible in (g)Vim to move the cursor to its previous position (while in normal mode)? Something to cycle back and forth in the list of previous cursor positions would be ideal. But also just to switch to the last location would suffice (something like cd - in bash with directories).
Here's a little demonstration:
line |1| <- cursor position
line 2
line 3
line 4
And suppose I did 2j, here's how it is now:
line 1
line 2
line |3| <- cursor position
line 4
Now I'd like to press something (other than 2k obviously) to move back to the first position and possibly to previous positions.
The quickest way is to hit either:
''
(two apostrophes) or:
``
(two backticks). Note that the difference is that the backtick goes to the same location on the line, whereas the apostrophe goes to the start of the line. On a UK keyboard, the apostrophe is more accessible, so I tend to use that one. There are loads of useful marks like this, see :help mark-motions.
For some other motions (not 2j I think), there's also the jump-list that lets you navigate back and forth among a number of motions. CtrlO and CtrlI do this navigation, but see :help jump-motions for more information.
You can also use g; and g, to move back- and forward in the list of your previous edit locations.
On Non-US Keyboards
On my Swiss and German keyboard layouts, typing ; inconveniently requires using the Shift key. Hence, I defined g- as a more convenient alias for g; in $MYVIMRC:
" Map g- as an alias for g;
nnoremap g- g;
Why no one figured out the problem with DrAl's answer?
The '' or `` will not solve the original problem of this post!
These two command will not work for some cursor movement like 2j, at least for me. It will make newbie to vim more confused.
The behavior of '' or ``, and CtrlI or CtrlO are based on jump list. The 2j will not save the position changes into the jump list so these command will not work for 2j.
'' or `` switch between the last position and the current position.
CtrlI and CtrlO work through the jump list history.
g; and g, move through edit positions, which are also very frequently used.
Right from the help (:help jump):
:ju[mps] Print the jump list (not a motion command). {not in
Vi} {not available without the |+jumplist| feature}
*jumplist*
Jumps are remembered in a jump list. With the CTRL-O and CTRL-I command you
can go to cursor positions before older jumps, and back again. Thus you can
move up and down the list. There is a separate jump list for each window.
The maximum number of entries is fixed at 100.
{not available without the |+jumplist| feature}
I like the functionality of <C-O> and <C-I> to go back and forth to different positions. But many times I would prefer to stay within the current buffer, and always get taken by surprise when a new buffer opens up replacing the one I was looking at.
(1) Is there a way to achieve this? i.e., limit <C-O> and <C-I> to the same buffer?
(2) Is there a way to visit all cursor moves, even those that are not normally considered jumps, e.g. 10k?
As for moving in the same file, check out the '' command. It will jump back and forth between the current location and the last jump.