Reputation: 329
I often transform lines of texts to arrays. For example, this:
Monday
Tuesday
Wednesday
Becomes:
[
'Monday',
'Tuesday',
'Wednesday',
]
I can make a map that changes one of the lines (e.g. Monday
to 'Monday',
) like so:
:nnoremap gsa ^i'<Esc>A,
What I'd like to do is have that command take a movement or a text object so that I can execute it like gsaip
or gsip3j
.
How can I accomplish this?
Upvotes: 7
Views: 2269
Reputation: 32926
If you really want to add a comma after the last item, I would have done it this way, in order to leave registers unaltered.
function! s:to_list() range abort
let words = getline(a:firstline, a:lastline)
exe a:firstline.','.a:lastline.'d _' " remove the "_" to fill the unnamed register
let lines = ['['] + map(words, '" ".string(v:val).","') + [']']
call append(a:firstline-1, lines)
endfunction
command! -nargs=0 -range=% ToList <line1>,<line2>call s:to_list()
In order to get rid of the last two lines, I've edited the last item of map()
result or played with join()
:
let lines = "[\n" . join(map(words, '" ".string(v:val)'), ",\n") . "\n]"
put!=lines
Upvotes: 0
Reputation: 59287
You can use 'operatorfunc'
with g@
to have a map with a
motion. The help gives a full explanation and example under the
:map-operator
topic. Basically you set the function you want to
call in your map and use g@
. Vim will wait to a motion and then set
the marks '[
and ']
and call your function.
Inside your function you can go creative, here I just made a quick example of how you could apply this principle to what you need.
:nnoremap <silent> gsa :set opfunc=TransformToArray<cr>g@
function! TransformToArray(type)
if a:type == 'line'
let s=line("'[") " saving beginning mark
']s/\(\s*\).*\zs/\r\1]
exec s ",']-1s/\\s*\\zs.*/ '&',"
exec s 's/\(\s*\)\zs\ze /[\r\1'
elseif a:type == 'char'
" ...
endif
endfunction
Upvotes: 7
Reputation: 6421
Put this into your .vimrc
file :
vnoremap <silent> gsa :call Brackets()<CR>
function! Brackets()
execute "normal! I'"
if line(".") == a:lastline
execute "normal! A'\<cr>]"
execute a:firstline."s:^:[\r:"
else
execute "normal! A',"
endif
endfunction
Select the visual-line block you want for example vip
and then press gsa
.
Upvotes: 1
Reputation: 172520
To be precise, you seem to want to apply the mapping to each of the lines covered by a motion or text object.
You can establish such range via visual mode: vip
or v2j
. Then, you can use :normal gsa
(typed; Vim automatically inserts the selected range (:'<,'>
) if you enter command-line mode from visual mode) to apply your custom mapping to each of the lines (the cursor is positioned on the first column for each line, as per :help :normal-range
).
Upvotes: 0