Move text surrounded by brackets to left or right

Viewed 238

Does anyone know a vim script / helper / command, that let you move a text which is surrounded by brackets left or right within a line?

For example I have this text with chord annotations in it, and I want to have a shortcut, where I can move the chord inside the brackets, e.g.

Some lyrics and te[Am]xt line
                   ^
Some lyrics and t[Am]ext line
                  ^

This would be one move to the left.

I'm sure this is possible (I guess nearly everything is possible with vim), but I don't know how, and haven't found anything so far.

1 Answers

I'm not sure this is exactly what you want, but you could try the following code:

nno <silent> [h  :<c-u>call <sid>move_chords(0, v:count1)<cr>
nno <silent> ]h  :<c-u>call <sid>move_chords(1, v:count1)<cr>

fu! s:move_chords(fwd, cnt) abort
    let pos  = virtcol('.')
    let pat1 = '\[?\k{-}%#&(\[\k*\])('.repeat('.', a:cnt).')'
    let pat2 = repeat('.', a:cnt).'\[?\k{-}%#&('.repeat('.', a:cnt).')(\[\k*\])'
    exe 'keepj keepp s/\v'.(a:fwd ? pat1 : pat2).'/\2\1/e'
    exe &modified ? 'norm! '.(pos+(a:fwd ? a:cnt : -a:cnt)).'|' : ''
endfu

It should install 2 mappings, using the key sequences [h and ]h, to move the text inside square brackets around the current cursor position to the left or right. It should accept a count, if you want to move the text further away than a single character:

enter image description here

If you use the vim-repeat plugin, then, instead of repeating the same mapping, you could use the dot command:

enter image description here

... using a modified version of the previous code:

nmap <silent> [h                    <plug>(move_chords_backward)
nmap <silent> ]h                    <plug>(move_chords_forward)
nno <plug>(move_chords_backward)    :<c-u>call <sid>move_chords(0, v:count1)<cr>
nno <plug>(move_chords_forward)     :<c-u>call <sid>move_chords(1, v:count1)<cr>

fu! s:move_chords(fwd, cnt) abort
    let pos  = virtcol('.')
    let pat1 = '\[?\k{-}%#&(\[\k*\])('.repeat('.', a:cnt).')'
    let pat2 = repeat('.', a:cnt).'\[?\k{-}%#&('.repeat('.', a:cnt).')(\[\k*\])'
    exe 'keepj keepp s/\v'.(a:fwd ? pat1 : pat2).'/\2\1/e'
    exe &modified ? 'norm! '.(pos+(a:fwd ? a:cnt : -a:cnt)).'|' : ''
    sil! call repeat#set("\<plug>(move_chords_".(a:fwd ? 'forward' : 'backward').')', a:cnt)
endfu
Related