Vim: move around quickly inside of long line - vim

I have word-wrap enabled and tend to have quite long lines.
But moving around inside a line that's actually 4 lines high with "w" is cumbersome. I keep using / to jump to the word I'm looking for, but that seems overdoing it a bit.
Any hints on how to move more quickly inside of a line?
Thanks,
MrB

You can use $, 0, and ^ to move to line endpoints and then use w and b. Also, adding a numeric argument to w and b can accelerate the process, so using 6w instead of just w can put you about to where ou need to be.
Using f and t to move to individual characters will help also. (I use this typically with punctuation. If, for example, I have four sentences on one long line 2f. will go to the end of the second sentence)
Using the ( and ) keys are an alternative way to navigate entire sentences.
Splitting out long lines into multiple lines (manually, or with set tw=72 [or 80]) can make editing them simpler. You can always join them later with J.
Something I just discovered, you can move up and down one displayed line by using gj and gk. That way, you can treat your one wrapped line as multiple lines.
If you comment on the type of data you're editing, it might make it easier for us to make suggestions.

I think you can benefit from gk and gj instead of just k and j.
Also look at 'virtualedit' for some options that allow you to cursor through 'void' areas without flicking the cursor to the next best physical character.
You might want to (temporarily)
nnoremap <buffer> k gk
nnoremap <buffer> j gj
Leave out the <buffer> part to apply this globally.

You can use ( and ) to navigate by sentence; it just looks for ., but that can be immensely helpful, especially if you don't like the sentence and want to change it: (c) will jump to the beginning of the current sentence, then change the entire sentence.
You can also use w and e, with count modifiers, to move words. 3w will move three words at a time.
You can also use f and F to search forward and backwards for a specific character. This is much more useful if you're looking for the word quite or syzygy than the. :)

My preferred strategy while jumping around long lines is to use f F and t T to zero in on the character. What makes this family of motions supercharged is that you can utilize the ; and , motions, so you don't have to count the position of character relative to cursor, but just step through them (extremely useful with
' " . etc)
Let's say we have a line:
reallyLongObjectName.longMethod().prettyPrettyLongMethod().burp();
If we need to jump to, say, the third dot from the beginning of the line, we can use either 3f. or f.;; visiting two dots and landing on third.
While the ; , style can use more keystrokes, I found it more agile and fun overall.

If you choose to go the route of remapping these:
nnoremap k gk
nnoremap j gj
here are a couple others along the same lines:
nnoremap 0 g0
nnoremap $ g$
nnoremap ^ g^

I recently started using a plugin that I find really nice to move very quickly inside a line (or the whole file).
The plugin's name is PreciseJump and you can find it here.
When you use this plugin it defines to mappings _f and _F.
If you type _f followed by x it will highlight all x characters and will replace temporarily with other characters that you can press to jump to that location. Check the script page for an illustration.

You can also move around with W B that will skip to the next space :)
G moves to the end of the document

Please notice that using "g" followed by Up or Down arrows indeed works fine, but if you have long lines and move quickly you may enter "gg" by mistake and end-up at the top of the text...! (Undo will not bring you back, and AFAIK there is not one-key-pressed way to go back to where you were.)
It happened to me too many times.
What I did was, and I suggest you, to modify (or create) your "~/.vimrc" and add these two lines:
map <C-Up> g<Up>
map <C-Down> g<Down>
This will map you control-up and control-down to the movements commands. Will make mistyping "gg" impossible and is perfectly coherent with control-right and control-left to move around long lines.
If you add these other two lines, you can use the same command in insert mode (!)
imap <C-Up> <C-[> g<Up> i
imap <C-Down> <C-[> g<Down> i
(VIM is great !)
Greg Ruo

Related

Vim: Vertical "f" and "t"

One tiny piece of functionality I find myself missing increasingly often is the ability to move vertically in a similar fashion to f and t. Usually what I want is to move to the top or bottom of a paragraph without losing my column position, and while I "could" just write a script for it, I wondered if there is any known way around this problem that you guys know of.
Example ( [ ] = current position, < > = destination ):
set tabstop=4
set shiftwidth=4
set <s>ofttabstop=4
set gfn=Source\ Code\ Pro:h14
set encoding=utf-8
set [t]_Co=256
set number
Like a vertical fs, or t<space>.
Again, this is usually useful when working with blocks of code. Any ideas?
vim regex provides \%nc (n is col idx) to match only in certain column.
so without installing plugin, what you could do is :
nnoremap <leader>f :<c-u>exe line('.').'/\%'.col('.').'c'.nr2char(getchar())<cr>
in this way, you press <leader>f, then press a key, vim will search that char in the same col. next, you press n/N
If you want to have the same but search backwards, use ?.
The most basic way is to use forward search, /t_<CR> and backward search, ?so<CR>, ideally with set incsearch.
But there are quite a lot of plugins designed around that idea:
EasyMotion,
Sneak,
Fanfingtastic,
and a few others…
For moving vertically without changing columns, you can use <n>j or <n>k. That doesn't completely help with "top of paragraph" or "bottom of paragraph" without counting the lines. There's also '{' and '}' for jumping between paragraphs. Not sure there's a single command to do exactly what you want...
I recently implemented the JumpToVerticalOccurrence plugin (just published), which implements an f{char} equivalent as ]V{char}. It also has related mappings that jump to the same character the cursor is under, or to non-whitespace in the same column.
I have a mapping that might be useful in visual selection.
To extend the selection downwards (<leader>j) or upwards (<leader>k) from the current column, but not beyond the block of text:
vnoremap <leader>j <Esc>m`:let b:ss=#/<CR>:let b:zz=col('.') - 1<CR>/\%<C-r>=b:zz<CR>c.\zs.\+\n.\{,<C-r>=b:zz<CR>}$<CR>:let #/=b:ss<CR><C-v>``o
vnoremap <leader>k <Esc>m`:let b:ss=#/<CR>:let b:zz=col('.') - 1<CR>?^.\{,<C-r>=b:zz<CR>}\n.*\%<C-r>=b:zz<CR>c.\zs.<CR>:let #/=b:ss<CR><C-v>``o
It also avoids clobbering the search register. At least, that's how I avoid clobbering the search register.

Not highlighting search in vim if it is a part of a command

In my .vimrc I've enabled highlighting the searched text (which I find to be a handy feature and wouldn't want to disable it).
set hlsearch
And, following answers to this question, I've made a mapping to be able to clear the highlight:
nmap <silent> ,/ :nohlsearch<CR>
The problem comes with commands which include search. For example, delete to next character 'x':
d/x
This will automatically highlight all the instances of 'x'. To remove this highlight I have to punch ,/ to clear it, which is quite annoying.
The question. Is it possible to enforce :nohl if the search is a part of a preceding command? Maybe, it is possible at least for a selected list of commands (say, d, y and c) before / character is hit?
d/x does not work for me as you describe. (I'm on vim 7.3 here and it can't make sense of the / following d in normal mode, so disregards the d and starts a regular / search.)
If you want to delete to the next x, then dfx or dtx are what I would use (depending on whether you want to also delete the x itself or not).
No highlighting involved.
Hope that helps.
[Following some clarification in the comments.]
I'm thinking that it should be possible to write a custom function to do what you want, and then assign a custom key sequence to call that function.
I played around a little, but am not very well versed in vim functions and couldn't make it work.
Here's what I tried:
function! g:DeleteToSearchAndNohls(term)
:normal d/a:term
:nohlsearch
endfunc
If 'x' is on the same line than the cursor, you can use dtx (meaning delete to x).

Swap items in comma separated list

Frequently, e.g. when I write Latex code, I come across the task to rearrange items of a list that are separated by commas. This is quickly done if both items are not at the at the beginning or the end of the list. But if they are at the margins, one has to take extra care of the separating comma.
As an example consider
\cite{GirR84, Tar00, Tem77}.
Is there a smart way in vim to put, e.g., the last item to the front or to the middle position?
I actually made a plugin to deal with a similar situation called argumentative.vim. (Sorry for the plug.)
Argumentative.vim provides the following mappings:
[, and ], motions which will go to the previous or next argument
<, and >, to shift an argument left or right
i, and a, argument text objects. e.g. da,, ci, or yi,
So with this plugin you move to the argument in question and then do a <, or >, as many times as needed. It can also take a count e.g. 2>,.
If you have Tim Pope's excellent repeat.vim plugin installed <, and >, become repeatable with the . command.
I have the following mappings in .vimrc, I think I have them from this tip on wikia:
nnoremap <silent> gl "_yiw:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><c-o>/\w\+\_W\+<CR><c-l>
nnoremap <silent> gh "_yiw?\w\+\_W\+\%#<CR>:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><c-o><c-l>
gh will swap word under the cursor to the left and gl to the right.
Another interesting way of swapping arbitrary things from the Vim Tips Wiki:
:vnoremap <C-X> <Esc>`.``gvP``P
You could try the vim plugin vim-swap, quite powerful and useful!

Is there a way to get integer object motions in vim?

I often work on CSS files or other files that require twiddling numbers. I would love the ability to have a key that refers to integers much in the way that w refers to a word, or ( refers to a sentence. For example, in a css file I could navigate to the beginning of a height declaration, and change it's value without having to retype "px" a the end, which is what happens if I use w.
Is there such a thing, but I'm missing it in the documentation, or is there a way to add this functionality to my .vimrc?
Bonus points if there were a way to use it like ci" where I could be at the begining of the line and use the "change internal" command to jump to AND change the next integer.
More bonus points if I could do simple arithmetic. I would love to be able to issue a concise command that was short for "Add too, internal, integer, 5" and have the next integer on the current line be five grater then it was when I started.
Edit:
Some really great proposals everyone, some great ideas that are sure to improve my work. Thanks! Hassek's answer is probably the most likely to end up in my work-flow, but none of the others seem to have (fully) answered my inital question: A motion that works on integers. The proposal tracked down by romainl appears to have that goal, but I can't get it to work reliably.
For myself (and others perhaps) I will clarify my wants below:
A key that acts much in the way w acts for words, but on integers so that I can simply add it to my mental vim vocabulary and use it seamlessly. This includes the following scenarios. (I will use d as my example key):
Normal mode d: Jump to the next integer
Normal mode cd: Change to the end of the integer under the cursor (Note that cw is a special case that SHOULD change to the NEXT word. cw actually acts like ce.) I would expect this special case to be implemented with integers as well
Visual mode id: Select [count] integers.
Visual mode ad: Select [count] integers. Leading or trailing white space is included.
Am I missing any behavior that w has that might be expected for a new motion? Is there even a key available in both normal and visual modes?
you can add or substract from integers using this commands:
<num>Ctrl-a (to add)
<num>Ctrl-x (to substract)
and it will go right to the next number in line and execute the command
See this proposal. It looks good.
edit
Indeed that one is quite nice. This made me think that my habit of doing /<number><Esc> was not very efficient so I've added these mappings (and slightly modified the mappings above for consistency) to my ~/.vimrc. Let's see if they are useful in the long run:
nnoremap è /\v\d+<CR>
nnoremap é ?\v\d+<CR>
At first sight, èciè132<Esc> seems to be marginally better than /2<Esc>{count}s132<Esc> in terms of keypresses but substantially better if it allows me to skip a. checking the first digit of the value I want to change and b. counting the characters to replace.
Time will tell.
re-edit
Here are the function and its mappings:
onoremap N :<c-u>call <SID>NumberTextObject(0)<cr>
xnoremap N :<c-u>call <SID>NumberTextObject(0)<cr>
onoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
onoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>
function! s:NumberTextObject(whole)
normal! v
while getline('.')[col('.')] =~# '\v[0-9]'
normal! l
endwhile
if a:whole
normal! o
while col('.') > 1 && getline('.')[col('.') - 2] =~# '\v[0-9]'
normal! h
endwhile
endif
endfunction
With this, I can:
vcdy part of a number from the cursor until its end with <command>N. Somehow similarly to <command>e or <command>w.
Here are some random numbers: 24 7635 1000018
^--->
It doesn't work if the cursor is not already on the number and it doesn't go backward.
vcdy a whole number with <command>iN.
Here are some random numbers: 24 7635 1000018
<-^--->
Again, it doesn't work if the cursor is not already on the number.
The whole thing could be improved, sure, but that's a start!
endedit
I work a lot with CSS, too.
I use two strategies to change numerical values:
{count}<C-a> and {count}<C-x>, as in Hassek's answer, when I know by how much I want to increment/decrement the number. Say I want to turn 20px into 25px, a simple 5<C-a> does the trick without requiring me to move the cursor to the number. This is extremely cool.
/<number><CR>{count}s<new number> when the new value is very different from the current value and I feel to lazy to calculate the delta. /2<CR>2s67<Esc> would allow me to change 23px into 67px. /2<CR>R67<Esc> is another way but it's only good if the new value as the same length as the current value. Use f<number> if you are on the same line.
Note that you can insert the result of expressions with <C-r>=137-42<CR> which I use it very often as well.
I found something in the depths of the internetz here and modified it like this
nnoremap ,n /\v\d+/b<cr>mah/\v\d+/e<cr>mb`av`b
vnoremap ,n <esc>/\v\d+/b<cr>mah/\v\d+/e<cr>mb`av`b
\v\d+ searches for a group of digits
/b + mah goes to its beginning, sets a mark and goes one character back so we can again
\v\d+ search for the same group of digits
/e + mb goes to its end and sets another mark and at last
`av`b visually selects from the first to the second mark

How to emulate Emacs’ transpose-words in Vim?

Emacs has a useful transpose-words command which lets one exchange the word before the cursor with the word after the cursor, preserving punctuation.
For example, ‘stack |overflow’ + M-t = ‘overflow stack|’ (‘|’ is the cursor position).
<a>|<p> becomes <p><a|>.
Is it possible to emulate it in Vim? I know I can use dwwP, but it doesn’t work well with punctuation.
Update: No, dwwP is really not a solution. Imagine:
SOME_BOOST_PP_BLACK_MAGIC( (a)(b)(c) )
// with cursor here ^
Emacs’ M-t would have exchanged b and c, resulting in (a)(c)(b).
What works is /\w
yiwNviwpnviwgp. But it spoils "" and "/. Is there a cleaner solution?
Update²:
Solved
:nmap gn :s,\v(\w+)(\W*%#\W*)(\w+),\3\2\1\r,<CR>kgJ:nohl<CR>
Imperfect, but works.
Thanks Camflan for bringing the %# item to my attention. Of course, it’s all on the wiki, but I didn’t realize it could solve the problem of exact (Emacs got it completely right) duplication of the transpose-words feature.
These are from my .vimrc and work well for me.
" swap two words
:vnoremap <C-X> <Esc>`.``gvP``P
" Swap word with next word
nmap <silent> gw "_yiw:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<cr><c-o><c-l> *N*
Depending on the situation, you can use the W or B commands, as in dWwP. The "capital" versions skip to the next/previous space, including punctuation. The f and t commands can help, as well, for specifying the end of the deleted range.
There's also a discussion on the Vim Tips Wiki about various swapping techniques.
In the middle of a line, go to the first letter of the first word, then do
dw wP
At the end of a line (ie the last two words of the line), go to the space between the words and do
2dw bhP
From the handy Equivalence of VIM & Emacs commands
You could add shortcut keys for those by adding something like the following to your vimrc file:
map L dwwP
map M 2dwbhP
In that case, SHIFT-L (in command-mode) would switch words in the middle of the line and SHIFT-M would do it at the end.
NB: This works best with space-separated words and doesn't handle the OP's specific case very well.
There's a tip on http://vim.wikia.com/wiki/VimTip10. But I choose to roll my own.
My snippet has two obvious advantages over the method mentioned in the tip: 1) it works when the cursor isn't in a word. 2) it won't high-light the entire screen.
It works almost like emacs 'transpose-words', except that when transposition is impossible, it does nothing. (emacs 'transpose-words' would blink and change cursor position to the beginning of current word.)
"transpose words (like emacs `transpose-words')
function! TransposeWords()
if search('\w\+\%#\w*\W\+\w\+')
elseif search('\w\+\W\+\%#\W*\w\+')
endif
let l:pos = getpos('.')
exec 'silent! :s/\(\%#\w\+\)\(\W\+\)\(\w\+\)/\3\2\1/'
call setpos('.', l:pos)
let l:_ = search('\(\%#\w\+\W\+\)\#<=\w\+')
normal el
endfunction
nmap <silent> <M-right> :call TransposeWords()<CR>
imap <silent> <M-right> <C-O>:call TransposeWords()<CR>
You can use dwwP or dWwP as Mark and CapnNefarious have said, but I have a few notes of my own:
If the cursor is on the first letter of the second word, as in the example you gave, you can use dwbP (or dWbP to handle punctuation);
If the cursor is in the middle of the word, you can use dawbP/daWbP.
There's a transpose-words script on vim.org that works beautifully.

Resources