Reputation: 10939
I am writing a vimscript function to wrap the currently selected lines (visual mode) in a Ruby begin-rescue block. I am getting some strange behavior. Here is my function:
function! BeginRescueWrap()
execute "normal! gvd"
let head = "begin\<CR>"
let body = @"
let tail = "rescue StandardError =>e\<CR>binding.pry\<CR>end\<CR>"
execute "normal! i" . head . "\<CR>" . body . "\<CR>" . tail
endfunction
It almost works-- it just produces two copies of the head and tail for some reason. For example, running the function when this text is selected:
Oh lord won't you buy me a Mercedes Benz
My friends all drive Porsches, I must make amends
Produces this output:
begin
begin
rescue StandardError =>e
binding.pry
end
Oh lord won't you buy me a Mercedes Benz
My friends all drive Porsches, I must make amends
rescue StandardError =>e
binding.pry
end
I don't care about the indentation (can fix that later). Just notice that there is an outer wrapping that includes an empty inner wrapping followed by the target lines. What am I doing wrong?
Upvotes: 0
Views: 225
Reputation: 6332
The problem is that Vim will execute your method twice, because you selected 2 lines. If you add the range
parameter to the method it will only be executed once, and you will have your desired effect:
function! BeginRescueWrap() range
execute "normal! gvd"
let head = "begin\<CR>"
let body = @"
let tail = "rescue StandardError =>e\<CR>binding.pry\<CR>end\<CR>"
execute "normal! i" . head . "\<CR>" . body . "\<CR>" . tail
endfunction
Note though that for this specific purpose, a mapping like this would probably be more concise:
vnoremap ,q sbegin<cr><C-R>1rescue StandardError =>e<cr>binding.pry<cr>end<cr>
This mapping for ,q
removes the currently selected text, writes the begin
statement, then puts what was just deleted, then writes your ending ending.
Upvotes: 4