How to emulate Emacs’ transpose-words in Vim? - 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.

Related

Swap two characters atomically, so that it can be repeated with "."

The idiom for swapping two characters in Vim is xp.
See the help at :h 04.5, final paragraph, and Vim: how do I swap two characters?.
But very occasionally I need to do two or more swap operations in a row. I'm often surprised that what feels like a single operation to me, xp, is actually two operations to Vim. This makes it impossible to repeat xp with .. (Or atomic undo with u.)
Is there a way to swap two characters in a single operation that I can quickly repeat with .?
This isn't ideal, but if you store xp as a macro, it will be repeatable after you've executed the macro. So instead of xp, you're using, say #s (for swap). Then ## will repeat it. Not as nice as ., but it does work.
Edit: You know, I'm sure there's a way to accomplish this with some vimscript and tpope's repeat.vim. Sadly, my vimscript is not up to snuff. I got this far - maybe someone can correct where I'm going wrong?
fun! DoSwap()
:normal xp
silent! call repeat#set("\<Plug>Swap",1)
endfun
nnoremap <silent> <Plug>Swap :call DoSwap()<CR>
nmap <Leader>s <Plug>Swap
The problem with this is that once you enter \s, it does indeed swap the characters you're on, and it DOES repeat when you hit ., but it jumps to the beginning of the line first, which is not what you want. But I do think this can be done, I'm just not all the way there.
Here's an idea. Suppose the cursor is on the "y" of the word "oyxgen".
In normal mode, type
2sxy<Esc>
Now the word reads "oxygen". Find the next instance of the typo (fy) and repeat the change (.).
Too bad this works only for the specific swap "yx" to "xy", so this isn't the definitive solution.
Vimcasts.org has published an episode that addresses this very problem.
As #Jeremy guessed the solution is to use the repeat.vim plugin. Then simply add the following <Plug> mapping and key mapping to your vimrc.
nnoremap <silent> <Plug>Transpose xp:call repeat#set("\<Plug>Transpose")<CR>
nmap cp <Plug>Transpose
The mapping shown here uses cp. cp is the new xp, repeatable with . but otherwise exactly the same.
Now all that remains is getting used to it.

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

Using alt+backspace key in vim command line to delete by words

Is there a way to use the alt+backspace in vim command line? It gets unruly when having to backspace /very/long/file/path individually instead of using alt+backspace to delete by words.
try using instead <c-w> (that is ctrl+w) to erase words or <c-u> (ctrl+u) to delete lines.
http://vim.wikia.com/wiki/Map_Ctrl-Backspace_to_delete_previous_word
:imap <C-BS> <C-W>
sets ctrl backspace, i have to look at how to do alt
If you are at the end of the path you can hit B followed by a dW (case matters). This will jump you to the beginning of the word (ignoring the slashes) and subsequently delete the word (again ignoring the slashes).
Hope this helps.
Vim is unable to receive alt input. skeept's answer seems to be the best alternative.
See this answer:
The Alt/Meta key is problematic in Vim and most terminals, see this answer of mine for an overview of the situation (the situation is the same for Meta and Alt).
In short, Vim doesn't receive Alt at all: hitting Alt+Backspace is exactly the same as hitting Backspace.
Anyway, it will be better for you in the long term to learn and get accustomed to Vim's default key-mappings.
The answer marked as right does not correspond to the behaviour in most UI editors for Alt + BackSpace. The vim shortcut which correspond to this behaviour is db - aka delete back ( a word ?! ), dw would delete word forth, which would be the (Altr or Ctrl ) Del shortcut in most ui programs.
Those work basically the same way as the w - move the cursor to the words beginnings and b, move the cursor back to the words beginning ...
Disclaimer: I have used for more than 10 years my .vimrc. , which might have some freaky twist which changes the default behaviour as well ...
Sure, it's as easy as:
if has('gui_running')
imap <M-BS> <C-W>
else
imap <Esc><BS> <C-W>
endif
The trick here is to know, given a hypothetical foo key, that after pressing a Alt+foo combination, many terminals will send an Escape code followed by foo. Apparently there are exceptions — some terminals do send something that vim can recognize as Alt. But if a imap <M-BS> <C-W> mapping doesn't work for you in terminal, then most likely your terminal sends an Esc instead, so the combination imap <Esc><BS> <C-W> should work for you.
You can read more about that in vim documentation by evaluating :help map-alt-keys
x then w should backspace per word as well.
d then w will also delete the current word the cursor is on.

Vim: move around quickly inside of long line

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

In vim, is there a way to rebind "*" to highlight the current word, without advancing to the next? [duplicate]

This question already has answers here:
Vim: search and highlight but do not jump
(14 answers)
Closed 4 years ago.
I often use * to highlight all instances of the current word, and the fact that it advances to the next word is pretty annoying. I'd like to disable this behavior, knowing that I can always use "n" if I actually need to advance.
Any insight?
EDIT: I should add that I'd like to avoid a screen redraw at all costs as it is visually distracting.
Try this:
nnoremap * :let #/ = "\\<<C-R><C-W>\\>"<CR>
(Assumes you have 'hlsearch' on). This just changes the current search pattern to the word under the cursor (surrounded by \< and \> to match word boundaries). If you have hlsearch enabled, it will highlight the word. n and N will then work as normal.
See:
:help :let-#
:help quote/
:help c_CTRL-R_CTRL-W
Try this Vim Tip. I find it very useful. The most interesting is that you can have more matches and every one in different color.
I cannot give an exact answer, but this Vim Tip tells you what you have to add to your .vimrc to simply highlight the word under the cursor when Vim is in idle state.
Works without any key-remapping...
You can remap it to return:
nnoremap * '*N'
(but this redraws the screen)

Resources