116

I am writing Python code using Vim, and every time I want to run my code, I type this inside Vim:

:w !python

This gets frustrating, so I was looking for a quicker method to run Python code inside Vim. Executing Python scripts from a terminal maybe? I am using Linux.

multigoodverse
  • 5,876
  • 11
  • 51
  • 93

23 Answers23

170

How about adding an autocmd to your ~/.vimrc-file, creating a mapping:

autocmd FileType python map <buffer> <F9> :w<CR>:exec '!python3' shellescape(@%, 1)<CR>
autocmd FileType python imap <buffer> <F9> <esc>:w<CR>:exec '!python3' shellescape(@%, 1)<CR>

then you could press <F9> to execute the current buffer with python

Explanation:

  • autocmd: command that Vim will execute automatically on {event} (here: if you open a python file)
  • [i]map: creates a keyboard shortcut to <F9> in insert/normal mode
  • <buffer>: If multiple buffers/files are open: just use the active one
  • <esc>: leaving insert mode
  • :w<CR>: saves your file
  • !: runs the following command in your shell (try :!ls)
  • %: is replaced by the filename of your active buffer. But since it can contain things like whitespace and other "bad" stuff it is better practise not to write :python %, but use:
  • shellescape: escape the special characters. The 1 means with a backslash

TL;DR: The first line will work in normal mode and once you press <F9> it first saves your file and then run the file with python. The second does the same thing, but leaves insert mode first

Michael
  • 537
  • 3
  • 19
Kent
  • 173,042
  • 30
  • 210
  • 270
  • 6
    Can you please expand your answer and explain where should I add that line. Inside a Vim configuration file maybe? I am a newby. – multigoodverse Sep 22 '13 at 20:50
  • 5
    @ArditSulce in your vimrc file, add a line: `autocmd FileType python nnoremap .... ` – Kent Sep 22 '13 at 21:04
  • 2
    If you're on os x (and I assume unix) ".vimrc" is in the home directory. You can check this by typing ':version' in command mode to check for sure you'll see a line called 'user vimrc file: "..."' – ThinkBonobo Jun 27 '15 at 19:50
  • Is there a way to save and run the same file, instead of just running it – Bharat Aug 28 '16 at 21:33
  • @Bharat maybe this should work `nnoremap :exec 'w !python' shellescape(@%, 1)` – Ashok Arora Jan 12 '17 at 16:14
  • 5
    `nnoremap :!python %` seems to work in Vim 7.4.1689. What's the shellescape for? – Matt Kleinsmith Apr 02 '17 at 03:50
  • @MatthewKleinsmith after all, your python src is a file. A file name can contain many interesting characters. – Kent Jul 13 '17 at 09:10
  • @Kent is it possible to yank something in vi and pass it to a python function. i think that i have seen this defined to add a column of numbers, but never managed to do it :( – Alexander Cska Dec 22 '18 at 17:40
  • @AlexanderCska yes, it is possible. you can read the `"` register to get the yanked text. – Kent Jan 16 '19 at 08:38
  • I noticed this command only works while the file is opened. Once I close the file and reopen it I can no longer press F9 to run the file. Is there any way to permanently allow F9 to run a Python script in Vim? – user117294 Dec 02 '19 at 00:56
  • What does the `@` symbol do? I can't find an explanation for it. – brainplot Apr 28 '20 at 08:45
  • @Kent I tried that, no luck: `Execute the contents of register {0-9a-z".=*+} [count] times. Note that register '%' (name of the current file) and '#' (name of the alternate file) cannot be used.` Not very useful, given the fact it says `%` doesn't apply. – brainplot Apr 28 '20 at 09:02
  • @brainplot sorry, my bad, I didn't read it carefully. It is to get the value of a register. The doc is here: `:h expression-syntax` you may want to read `expr9`carefully. – Kent Apr 28 '20 at 09:23
  • @user117294 conversely, this only worked for me once I closed my .py file and reopened it (I think due to the option). Did you add the autocmd to your ~/.vimrc? – Ralph Apr 30 '20 at 02:57
  • An improvement would be exchanging `:w` for `:up`, because update only writes the buffer if it has changed. – SergioAraujo May 09 '20 at 18:12
  • Great answer, thank you. I replace `'!python3'` with `'!/usr/bin/env python3'` for the reasons [outlined here](https://stackoverflow.com/a/2429517), and would encourage others to consider doing so too – jwalton Jun 10 '20 at 12:22
46

Just go to normal mode by pressing <esc> and type:

! clear; python %

enter image description here

Step by step explanation:

! allows you to run a terminal command

clear will empty your terminal screen

; ends the first command, allowing you to introduce a second command

python will use python to run your script (it could be replaced with ruby for example)

% concats the current filename, passing it as a parameter to the python command

Flavio Wuensche
  • 7,326
  • 1
  • 44
  • 45
30

I have this in my .vimrc file:

imap <F5> <Esc>:w<CR>:!clear;python %<CR>

When I'm done editing a Python script, I just press <F5>. The script is saved and then executed in a blank screen.

czayas
  • 425
  • 4
  • 6
22

I prefer Python output redirected to a new Vim window (and if that window is left open then update its content the next time you execute Python code with this function):

" Bind F5 to save file if modified and execute python script in a buffer.
nnoremap <silent> <F5> :call SaveAndExecutePython()<CR>
vnoremap <silent> <F5> :<C-u>call SaveAndExecutePython()<CR>

function! SaveAndExecutePython()
    " SOURCE [reusable window]: https://github.com/fatih/vim-go/blob/master/autoload/go/ui.vim

    " save and reload current file
    silent execute "update | edit"

    " get file path of current file
    let s:current_buffer_file_path = expand("%")

    let s:output_buffer_name = "Python"
    let s:output_buffer_filetype = "output"

    " reuse existing buffer window if it exists otherwise create a new one
    if !exists("s:buf_nr") || !bufexists(s:buf_nr)
        silent execute 'botright new ' . s:output_buffer_name
        let s:buf_nr = bufnr('%')
    elseif bufwinnr(s:buf_nr) == -1
        silent execute 'botright new'
        silent execute s:buf_nr . 'buffer'
    elseif bufwinnr(s:buf_nr) != bufwinnr('%')
        silent execute bufwinnr(s:buf_nr) . 'wincmd w'
    endif

    silent execute "setlocal filetype=" . s:output_buffer_filetype
    setlocal bufhidden=delete
    setlocal buftype=nofile
    setlocal noswapfile
    setlocal nobuflisted
    setlocal winfixheight
    setlocal cursorline " make it easy to distinguish
    setlocal nonumber
    setlocal norelativenumber
    setlocal showbreak=""

    " clear the buffer
    setlocal noreadonly
    setlocal modifiable
    %delete _

    " add the console output
    silent execute ".!python " . shellescape(s:current_buffer_file_path, 1)

    " resize window to content length
    " Note: This is annoying because if you print a lot of lines then your code buffer is forced to a height of one line every time you run this function.
    "       However without this line the buffer starts off as a default size and if you resize the buffer then it keeps that custom size after repeated runs of this function.
    "       But if you close the output buffer then it returns to using the default size when its recreated
    "execute 'resize' . line('$')

    " make the buffer non modifiable
    setlocal readonly
    setlocal nomodifiable
endfunction
Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
FocusedWolf
  • 882
  • 13
  • 17
  • Should I enter this right into my `.vimrc`? If not, how should I give this script to vim? (Noob here) – Benjamin Chausse Feb 27 '19 at 14:23
  • 1
    @BenjaminChausse Sorry for the delayed response. I did a test with a .vimrc that contained exclusively that code and it worked from what i could tell. My testing was limited to opening a .py file and hitting F5 which resulted in python output appearing in a separate vim window. "how should I give this script to vim?". It depends on your OS. I'm using Windows so i have a C:\Program Files (x86)\Vim\.vimrc text file which contains that code (you could also name it "_vimrc" in Windows). In Linux or mac you would have a .vimrc text file in your home folder i.e. ~/.vimrc – FocusedWolf Mar 03 '19 at 04:11
  • 4
    While we appreciate that this may have taken you a lot of work to create, putting in paypal links into an answer isn't really appropriate. – Martijn Pieters Nov 09 '19 at 16:27
  • How do you exit after running F5? – Eric O. Apr 19 '21 at 07:17
  • @eric-o Ctrl-C to terminate a script if its running. To close the "F5" window, like any other Vim window, first focus it (either click it or Ctrl + w and w to cycle windows) and press Control + w and q to close the window. – FocusedWolf Apr 22 '21 at 19:13
12

Building on the previous answers, if you like to see the code while looking at its' output you could find :ter (:terminal) command useful.

autocmd Filetype python nnoremap <buffer> <F5> :w<CR>:ter python2 "%"<CR>
autocmd Filetype python nnoremap <buffer> <F6> :w<CR>:vert ter python3 "%"<CR>

Using vert in the second line runs the code in vertical split instead of horizontal.

The negative of it is that if you don't close the split-window where the code ran you will have many splits after multiple runs (which doesn't happen in original python IDLE where the same output window is reused).

(I keep these lines inside /home/user/.vimrc)

michalmonday
  • 151
  • 1
  • 8
6

Plugin: jupyter-vim

So you can send lines (<leader>E), visual selection (<leader>e) to a running jupyter-client (the replacement of ipython)

enter image description here

I prefer to separate editor and interpreter (each one in its shell). Imagine you send a bad input reading command ...

Tinmarino
  • 2,995
  • 17
  • 30
5

Keep in mind that you're able to repeat the last used command with @:, so that's all you'd need to repeat are those two character.

Or you could save the string w !python into one of the registers (like "a for example) and then hit :<C-R>a<CR> to insert the contents of register a into the commandline and run it.

Or you can do what I do and map <leader>z to :!python %<CR> to run the current file.

TankorSmash
  • 11,146
  • 5
  • 55
  • 96
4

If you don't want to see ":exec python file.py" printed each time, use this:

nnoremap <F9> :echo system('python2 "' . expand('%') . '"')<cr>
nnoremap <F10> :echo system('python3 "' . expand('%') . '"')<cr>

It didn't mess up my powerline / vim-airline statusbar either.

Jabba
  • 15,755
  • 4
  • 43
  • 41
2

For generic use (run python/haskell/ruby/C++... from vim based on the filetype), there's a nice plugin called vim-quickrun. It supports many programming languages by default. It is easily configurable, too, so one can define preferred behaviours for any filetype if needed. The github repo does not have a fancy readme, but it is well documented with the doc file.

Yosh
  • 2,044
  • 1
  • 22
  • 28
2

The accepted answer works for me (on Linux), but I wanted this command to also save the buffer before running, so I modified it slightly:

nnoremap <buffer> <F9> :w <bar> :exec '!python' shellescape(@%, 1)<cr>

The :w <bar> saves the buffer THEN runs the code in it.

2

Think about using shebang line, so you will be able to use it with still any language, not only Python.

Adding shebang:

Add this to first line of your script:

#!/usr/bin/env python3

or this, if you are using Python 2:

#!/usr/bin/env python2

Vim keymap:

Add this to your ~/.vimrc:

nmap <F7> :w<cr>:!clear;"%:p"<cr>

Make file executable:

Type in Vim:

:!chmod +x %

or in terminal:

chmod +x script_name.py

Explanation:

When F7 is pressed in normal mode, Vim will try to execute current file as bash script. Then bash interpreter will see shebang line and understand, that this file should be passed to Python (or any other programm if needed).

Also you will be able to run your script from terminal using it's name:

./script_name.py

instead of this way (that will work too):

python3 script_name.py
Alex Kosh
  • 327
  • 1
  • 4
  • 7
  • I was thinking for a way to extend FucusedWolf answer to use the same time for both python2 and 3 versions, since I had to. Then yet again, this in combine with that would do. Thank you. – sajed zarrinpour Dec 09 '20 at 12:23
2

I use

:! [filename.py]; python %

That's what works for me

1

A simple method would be to type : while in normal mode, and then press the up arrow key on the keyboard and press Enter. This will repeat the last typed commands on VIM.

multigoodverse
  • 5,876
  • 11
  • 51
  • 93
  • You can do an incremental search by typing the starting characters of the command before pressing the up arrow. If many commands ago I did a ! python %, I could :! then press the up arrow, to only cycle through commands that start with ! – badteeth Mar 19 '14 at 19:54
1

If you want to quickly jump back through your :w commands, a cool thing is to type :w and then press your up arrow. It will only cycle through commands that start with w.

badteeth
  • 795
  • 7
  • 16
1

I have this on my .vimrc:

"map <F9> :w<CR>:!python %<CR>"

which saves the current buffer and execute the code with presing only Esc + F9

derwin
  • 19
  • 3
1

You can use skywind3000/asyncrun.vim as well. It is similar to what @FocusedWolf has listed.

Mike
  • 173
  • 1
  • 7
1

You can extends for any language with 1 keybinding with augroup command, for example:

augroup rungroup
    autocmd!
    autocmd BufRead,BufNewFile *.go nnoremap <F5> :exec '!go run' shellescape(@%, 1)<cr>
    autocmd BufRead,BufNewFile *.py nnoremap <F5> :exec '!python' shellescape(@%, 1)<cr>
augroup END

0

Put your cursor in the code somewhere. Right click and choose one of the "Select" choices to highlight your code. Then press Ctrl : and you will see the new prompt '<, >'

Now type !python and see if that works.

I just spend days trying to figure out the same problem!!! I used the coding:

s='My name'
print (s) 

After I pulled out all my hair, I finally got it right!

Steen
  • 5,653
  • 1
  • 37
  • 54
0

This .vimrc mapping needs Conque Shell, but it replicates Geany (and other X editors') behaviour:

  • Press a key to execute
  • Executes in gnome-terminal
  • Waits for confirmation to exit
  • Window closes automatically on exit

    :let dummy = conque_term#subprocess('gnome-terminal -e "bash -c \"python ' . expand("%") . '; answer=\\\"z\\\"; while [ $answer != \\\"q\\\" ]; do printf \\\"\nexited with code $?, press (q) to quit: \\\"; read -n 1 answer; done; \" "')

Steen
  • 5,653
  • 1
  • 37
  • 54
0

Instead of putting the command mapping in your .vimrc, put the mapping in your ~/.vim/ftplugin/python.vim file (Windows $HOME\vimfiles\ftplugin\python.vim). If you don't have this file or directories, just make them. This way the key is only mapped when you open a .py file or any file with filetype=python, since you'll only be running this command on Python scripts.

For the actual mapping, I like to be able to edit in Vim while the script runs. Going off of @cazyas' answer, I have the following in my ftplugin\python.vim (Windows):

noremap <F5> <Esc>:w<CR>:!START /B python %<CR>

This will run the current Python script in the background. For Linux just change it to this:

noremap <F5> <Esc>:w<CR>:!python % &<CR>
jpyams
  • 2,949
  • 3
  • 29
  • 56
0
" run current python file to new buffer
function! RunPython()
    let s:current_file = expand("%")
    enew|silent execute ".!python " . shellescape(s:current_file, 1)
    setlocal buftype=nofile bufhidden=wipe noswapfile nowrap
    setlocal nobuflisted
endfunction
autocmd FileType python nnoremap <Leader>c :call RunPython()<CR>
Neo Mosaid
  • 315
  • 1
  • 15
0
  1. Go to your home directory. cd
  2. Open your .vimrc file with vim. vim .vimrc
  3. Add the next code to the file. nmap <F4> <Esc>:w<CR>:!clear;python %<CR>
  4. Save it and quit. ZZ

The next time you want to run your code, just press F4 in "normal mode". If you want to run your code in "insert mode", replace nmap with imap.

0

Have you tried just using:

:!python nameofyourfile.py

example: https://www.youtube.com/watch?v=mjUxEX4OssM

It could just be your syntax, or it could be that you are missing pluggin or packages others have used. Are you using just plain terminal, or something else like MobaXterm? The above code works for running a python script using terminal inside vim (the output will show up inside the vim session).