Running Python code in Vim
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.
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. The1
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
Just go to normal mode by pressing <esc>
and type:
! clear; python %
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 withruby
for example)
%
concats the current filename, passing it as a parameter to thepython
command
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.
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