15

If I have a couple of lines of vimscript that I want to test before putting in my vimrc, is it possible to visually select, then source them?

I have tried

  • make visual selection v, then motions to make selection etc, then
  • :'<,'>so

But vim gives an error

no range allowed

also

:'<,'>w | so

gives

Use ! to write partial buffer

How can I source visually selected vimscript?

12

On the command line hit <C-u> then type @* and enter.

<C-u> will delete the visual range '<,'> that has been automatically inserted if some text is visually selected.

:@* will execute the content of the * register which contains whatever is visually selected at the moment.

Even if the text that is selected / highlighted is in your web browser (firefox, chrome, ...), it will work, the * register will allow you to access it directly in vim.


If your text is selected in a vim buffer, another solution is to copy it in a named register, for example the a register by typing "ay.

Then, on the command line, type : <C-r>a and enter.
Ctrl + r will give you a sort of prompt represented by the character " (for more information read :h c_Ctrl-r).
At this new prompt, if you give the name of a register, its content will be inserted on the command line, where you'll be able to edit it before execution.


Besides if you copy some text without specifying a register, it will be accessible from the unnamed register ".

So suppose you've got a line of vimscript in a file and want to source it quickly, you can copy it with Y, then source it on the command line with : :<C-r>" and enter.

Finally, if you use this last solution, there's just a problem you must be aware of.
If you see a strange character on the command line like this ^M, it's the caret notation of the carriage return. You should delete it, otherwise you'll probably get an error.

In summary, you :

  1. copy your line of vimscript with Y
  2. switch to command mode with :
  3. hit <C-r> to enter the registers prompt
  4. type " to call the unnamed register
  5. hit backspace to delete the ^M character
  6. and hit enter.
4
  • 1
    Sweet! :D works nicely - I had never come across the @* before, thanks! – the_velour_fog Nov 13 '15 at 11:12
  • I'm glad it helped you. I've edited the answer to propose another solution. – saginaw Nov 13 '15 at 11:20
  • 1
    nice one, I tried your suggestion about using : <C-r>a it actually worked fine too :) I guess vim read the ^M's as line returns - and executed each one as its own individual line / command? – the_velour_fog Nov 13 '15 at 11:54
  • That's a good question, honestly I don't know. Usually if I don't delete this character I've got errors. I'm glad it worked for you without errors. Maybe someone with more knowledge on the subject will explain to us how vim treats that kind of special characters. – saginaw Nov 13 '15 at 12:06
3

More directly to the question than my other answer, you could define a mapping to like this (nnoremap for no selection, just execute the current line; vnoremap for when visual mode is active):

nnoremap <F2> :execute getline(".")<CR>
vnoremap <F2> :<C-u>for line in getline("'<", "'>") \| execute line \| endfor<CR>

In both cases, the "current line" is :executed, so in the visual version you're :executeing one line after another through the visual selection.

As stated in another answer, the <C-u> deletes the range specification that pops up in the command line when : is typed. The | characters need to be escaped because otherwise they're interpreted as the end of the vnoremap command.

This could also be turned into a function to get rid of some of the escape gymnastics but it doesn't seem like a huge win to me at this time. It would basically be the vnoremap expanded into multiple lines and called with a range or not depending on the [nv] mapping mode.

1
  • Oh, the visual mode mapping executes entire lines so if you're block- or character-wise it'll ignore the start and end points within the lines. – dash-tom-bang Jun 6 '16 at 18:09
3

During development of vimscript code, having to source the whole file where it resides just to try out a snippet is sub-optimal. In my experience, there are always a bunch of variants of the code we're trying to make work that we don't want to throw out (yet), but we need to keep commenting it out (or in) so that the :so % doesn't trip up all over the place.

What is really wanted is not so much sourcing the file, but rather executing some snippet. Here is a function and a mapping that allow us to execute only the vimscript that is visually highlighted:

function! ExecHighlighted () range

        " Grab the highlighted text: save the contents of an arbitrary
        " register, yank the highlighted text to it, copy the register
        " contents to a local variable, and restore the register
        " contents.
    let l:saved_a = @a
    silent! normal! gv"ay
    let l:text = @a
    let @a = l:saved_a

        " Concatenate continuation lines, else for some reason it
        " fails to work.
    let l:text = substitute(l:text, '\n\s*\\\\', ' ', 'g')

        " Execute the grabbed text.
    exec l:text

endfunction

    " Have a Visual-mode-only mapping to invoke the function.
xnoremap <f9> :call ExecHighlighted()<cr>

So, visually select some text, press F9, and it will be executed.

The range argument ensures that the function is called only once even if the highlighted text has more than one line.

0
2

I actually do it a bit differently, I just make the edits in my vimrc and re-source it every time I write it. (I have a cascading set of vimrc files so this allows me to change any one of them.)

if $MYVIMRC != ''
    autocmd BufWritePost    *vimrc      source $MYVIMRC
endif
1

Note: Please use the other solution I posted instead of this kind of broken one.

Original post:

I have this mapping in my .vimrc to do precisely what you ask:

:vmap <f9> y:exec substitute(@", '\n\s*\\', ' ', 'g')<cr>

So, visually select some text, press F9, and it will be vim-compiled.

It has one important shortcoming: it fails if the vimscript to compile contains comments. Still, I find it extremely useful and have been using it regularly for years.

Explanation:

I'm writing it now, will edit this post when done.

4
  • 1
    Welcome to Vi and Vim! You might want to expand on your post to explain what it does and also why you use the substitute() with the regex on it. You might also want to consider using :xnoremap, which is more specific in that it only triggers in Visual mode (not Select mode) and it doesn't recursively use any other mappings you might have (so doesn't get interference from those.) – filbranden Mar 4 at 18:35
  • 1
    Thanks @guntbert for the improved formatting. I'll Learn more about formatting… and be more careful in the future. – lucs Mar 5 at 13:05
  • 2
    Thanks @filbranden for the suggested improvements. Reminded of my solution's main shortcoming (which in practical terms didn't really bother me before), I worked on it again and found something that works, for which I will post a new answer. I will also edit this answer to deprecate it and to explain how it works and why it fails. – lucs Mar 5 at 13:07
  • You forgot the explanation... – bew 2 days ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.