27

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')"

Charles
  • 455
  • 7
  • 13

3 Answers3

68

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.

DJMcMayhem
  • 7,285
  • 4
  • 41
  • 61
  • 2
    This is a perfect answer. SO is meant for teaching, not spoon-feeding. Thank you! – reergymerej Oct 19 '18 at 12:37
  • `: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. – Max Power Oct 14 '21 at 01:57
  • 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) – ptr64 Apr 04 '23 at 15:19
  • @ptr64 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 https://superuser.com/questions/157987/pipe-output-of-shell-command-into-a-new-buffer-in-vim – DJMcMayhem Apr 04 '23 at 22:03
  • 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? – ptr64 Apr 13 '23 at 20:19
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.

Community
  • 1
  • 1
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
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.

L3viathan
  • 26,748
  • 2
  • 58
  • 81