16

I'm not good enough at vim to determine whether this was possible or not (which is why I came to superuser and not good) ~ is there a way in vim to easily switch two words?

for example in def function(param1, param2) is there a quick/easy way to change that to def function(param2, param1)???

6 Answers 6

15

I don't remember where I originally got this, but it's been in my ~/.vimrc for at least a few years:

" Swap the word the cursor is on with the next word (which can be on a
" newline, and punctuation is "skipped"):
nmap <silent> gw "_yiw:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><C-o>:noh<CR>

After you have this defined, all you need to do is put your cursor somewhere on "param1" in normal mode and type: gw

1
  • 4
    I have it also, it comes from the vim wiki.
    – romainl
    May 30, 2011 at 6:48
8

That long solution is ugly. Suppose your cursor is at the left the first letter of the first word, that is 'p'. Do this: dwlpldw%p. This fits in your special case. How about dealing with daily editing? Try dwwP, or dWWP. :D

Tips: Don't always write long regular expression, if you don't need to do this often. Otherwise your vimrc booms. All vim users shall be familiar with its builtin cursor movement.

1
  • This is the way.
    – Bigger
    Sep 7, 2023 at 9:08
5

+1 for @Heptite's answer.

For more completeness, here is what I have in my .vimrc:

" push current line up or down
nnoremap <leader><Up> ddkP
nnoremap <leader><Down> ddp

" exchange character under cursor with the next character without moving the cursor
nnoremap gc xph

" exchange word under cursor with the next word without moving the cursor
nnoremap gw "_yiw:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><C-o><C-l>

" push word under cursor to the left
nnoremap <leader><Left> "_yiw?\w\+\_W\+\%#<CR>:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><C-o><C-l>

" push word under cursor to the right
nnoremap <leader><Right> "_yiw:s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<CR><C-o>/\w\+\_W\+<CR><C-l>

Source: the vim wiki.

I see my (and the wiki's) gw is slightly different from Heptite's one. I'm not sure which one is better.

1

I wrote up repeatable mappings using a combination of vim-exchange, Repeatable (which depends on repeat.vim), and argtextobj.

" Swap function arguments, move the argument under the cursor to the left or to
" the right.
Repeatable map <leader>al cxiaf,cxia
Repeatable map <leader>ah cxiaF,hcxia

The advantage in using the exchange and repeatable plugins for these mappings are:

  • Doing one undo u will undo the swap (they're atomic changes)
  • You can use the . to keep moving the argument left/right.

I know I know, it seems like a whole lot of plugins for a simple operation, but think what else those plugins give you:

  • argtextobj gives you the ia and aa textobj for deleting (dia and daa), and yanking (yia).
  • vim-repeat and Repeatable for making any of your mappings repeatable with ..
  • vim-exchange gives you repeatable, atomic exchanging of text.
1

Swap mappings for Latin languages

The swap mappings from the Vim wiki will not operate correctly on words with accented characters.

These mappings are adapted to work with (European) ISO/IEC_8859-1 Latin-1 Supplement characters. This is done by substituting all instances of \w in the Vim wiki code with [0-9A-Za-zÀ-ÖØ-öø-ÿ_\-] and all instances of \_W with \_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-].

Clearing of search highlighting

Furthermore, the search highlighting is cleared where needed. This is achieved by adding :nohlsearch<return> at the end of each mapping where it is required.

Here is the end result:

" Use gc to swap the current CHARACTER with the next, WITHOUT changing the cursor position.
nnoremap <silent> gc xph

" Use gw to swap the current WORD with the next, WITHOUT changing the cursor position.
nnoremap <silent> gw "_yiw:s/\(\%#[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\(\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\([0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)/\3\2\1/<CR><c-o><c-l>:nohlsearch<return>

" Disable Alt+[menukey] menu keys (i.e. Alt+h for help)
set winaltkeys=no

" Use Alt + ← or Alt + h to swap the current WORD with the previous, keeping the cursor on the current word. This feels like "PUSHING" the word to the left.
nnoremap <silent> <A-Left> "_yiw?[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\%#<CR>:s/\(\%#[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\(\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\([0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)/\3\2\1/<CR><c-o><c-l>:nohlsearch<return>
nnoremap <silent> <A-h>    "_yiw?[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\%#<CR>:s/\(\%#[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\(\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\([0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)/\3\2\1/<CR><c-o><c-l>:nohlsearch<return>
" <A-h> corresponds to è

" Use Alt + → or Alt + l to swap the current WORD with the next, keeping the cursor on the current word. This feels like "PUSHING" the word to the right.
nnoremap <silent> <A-Right> "_yiw:s/\(\%#[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\(\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\([0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)/\3\2\1/<CR><c-o>/[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+<CR><c-l>:nohlsearch<return>
nnoremap <silent> <A-l>     "_yiw:s/\(\%#[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\(\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)\([0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\)/\3\2\1/<CR><c-o>/[0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+\_[^0-9A-Za-zÀ-ÖØ-öø-ÿ_\-\`]\+<CR><c-l>:nohlsearch<return>
" <A-l> corresponds to ì

" Use g{ to swap the current PARAGRAPH with the next.
nnoremap g{ {dap}p{
0

Eclim plugin provides a good one. All credits to them :)

:SwapWords

.. and if you don't want to install the whole plugin, here is their function extracted:

" Swap words:
" taken from Eclim
" https://github.com/ervandew/eclim

function! SwapWords() " {{{
  " Initially based on http://www.vim.org/tips/tip.php?tip_id=329

  " save the last search pattern
  let save_search = @/

  normal! "_yiw
  let pos = getpos('.')
  keepjumps s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/
  call setpos('.', pos)

  " restore the last search pattern
  let @/ = save_search

  silent! call repeat#set(":call SwapWords()\<cr>", v:count)
endfunction " }}}

command! SwapWords :call SwapWords()

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .