Execute selection from script in Vim
Asked Answered
A

4

29

I'm trying to incorporate vim into my main workflow. A major sticking point for me has been interactively editing and running programs/scripts.

For example given that I'm currently vimmed into test.py

print('hello')
x = 5
y = x+2
print(y)

Without leaving vim how would I:
a) run the whole script without leaving vim
b) run just "print('hello')"

Animatism answered 27/10, 2016 at 16:20 Comment(1)
1) :!python3 test.py. 2) :!python3 -c "print('hello')".Kershaw
E
71

Commenters and the other answer have pointed out how to run a file from vim. But they glossed over some really powerful possibilities. I'd like to explain how some of those work in more detail.

The simplest possible way of running a python script in vim, is to just call the python interpreter on the file, e.g.

:!python %

or, as I prefer to do to make sure there are no unsaved changes,

:w | !python %

But it is not even necessary to have a file to run a python script in vim. The reason why is because :w != save! :w means write, and if no argument is provided, it happens to write to the file you are editing. However, you can write to STDOUT, to another file, or even to another program. So if you'd like to run your buffer as python code without having a file to save and run, you may simply do:

:w !python

This meanse write the current buffer into the external program "python". This literally just sends the contents of your buffer directly to python.

Now here's where it gets really cool. In vim, :w is an "ex command", e.g. a command that you run from the vim command line that originally came from ex, a very old line based unix text editor. The awesome thing about ex commands is that since they are all line based, you can directly state which lines you would like the command to apply to. For example:

:2w myfile.txt

will write only line two to the file "myfile.txt". You can even supply a range, e.g.

:2,7w myfile.txt

will write lines 2-7 to "myfile.txt". This means that using your example, we can run

:1w !python

to run just

print('hello')

To make this more convenient, you can use visual mode to select every line you would like to run, which will automatically fill in the right range for you. This will look like

:'<,'>w !python

To make this more convenient, I would recommend adding something like

xnoremap <leader>p :w !python<cr>

to your .vimrc. Then you can visually select whatever you want and run it as python code by typing

\p

(replace \ with whatever you have set up as your leader). You could also do

nnoremap <leader>p :w !python<cr>

or

nnoremap <leader>p :w | !python %<cr>

depending on whether you want to save to a file or not.

Envious answered 27/10, 2016 at 16:44 Comment(5)
This is a perfect answer. SO is meant for teaching, not spoon-feeding. Thank you!Thiol
:w !python3 encounters an EOF error at the first line with input() I'm guessing it has something to do with python waiting for user input and vim just dumping out the remaining buffer. But that is truly a wild guess.Witting
I know this is 6 years old but I learnt so much from this answer, so first off all, thank you! Secondly: I want to modify this behavior a bit more- e.g. sometimes I write code that needs to print a few hundred lines, can I make it print the output to a split tab, or even another window? (I'll make this a separate question if that would be more appropriate)Peale
@Peale I'm glad it's been helpful for you! It's nice to hear. As far as printing the output to a new buffer, that would be the :read command (or :r for short). See superuser.com/questions/157987/…Envious
If I try to pipe the output of a selection of lines using :tabnew | r '<,'>w !python I just get an empty tab. I tried saving the file and using :tabnew | r !python and :tabnew | r | w | !python % and just got empty tabs. Is it possible to chain the write and read commands?Peale
S
5

Create a function for a range as discussed in this question:

fu PyRun() range
  echo system('python -c ' . shellescape(join(getline(a:firstline, a:lastline), "\n")))
endf

Create a mapping for visual mode:

vmap <C-F6> :call PyRun()<CR>

Then you can select a range and press Control-F6. The range of lines will be executed by python. The result will be displayed in the command area.

Scammony answered 27/10, 2016 at 16:42 Comment(0)
K
3

You can run a program from vim using :!, i.e. :!python3 % to run your current script.

If you want to bind a key to it, another easy way would be to set makeprg to your python executable: :set makeprg=python3 and then bind a key to :make<cr>. In that case I would set up autocmds that switch the makeprg depending on the file type.

If you want to run a simple statement, you could either use Python's -c switch:

:!python3 -c 'print("Hello world")', or you could just run :!python3 without arguments to be dropped into a REPL without leaving Vim.

Kershaw answered 27/10, 2016 at 16:28 Comment(0)
N
0

Another gem in vim...

To run shell command + capture said command output, you could try 2 ways:

Using system function call

  1. Select target lines as shell commands
  2. run norm y (copies selected lines to vim unnamed register)
  3. run let @a = system (getreg('"')) (run commands stored in unnamed register, store result of command output to @a macro.
  4. run norm "ap (paste output from register to vim buffer)

Writing to shell as program

  1. run '<,'>w !bash | xclip (writing selected lines to bash as program and copying STDOUT to system clipboard)

This approach assumes xclip or equivalent utility/tool/cmdlet installed.

Novokuznetsk answered 26/4 at 1:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.