Do you want to quickly run and test any code without leaving Vim and without even opening a :terminal
?
There is a very simple way of achieving this. All we need is a runner function, a run command and a mapping to call it.
Here is an example:
function! CodeRunner()
if &ft ==# 'python'
execute 'RPy'
endif
endfunction
and the run command:
command! RPy :!python3 %
and the mapping:
nnoremap <F12> :call CodeRunner()<CR>
I prefer to wrap the mapping and the run command inside an augroup:
augroup code_runner
au!
au FileType python command! RPy :!python3 %
nnoremap <F12> :call CodeRunner()<CR>
augroup end
Place the above snippets in your .vimrc and source it. Now, every time you’re inside a python file, you can just press F12 to run the code and see its output.
You can add other languages to the function and to the augroup too:
"===[ Execute From Vim ]==="
function! CodeRunner()
if &ft ==# 'python'
execute 'RPy'
elseif &ft ==# 'sh'
execute 'RB'
elseif &ft ==# 'javascript'
execute 'RJs'
elseif &ft ==# 'php'
execute 'RPHP'
elseif &ft ==# 'go'
execute 'RGo'
endif
endfunction
And the corresponding augroup:
augroup code_runner
au!
au FileType python command! RPy :!python3 %
au FileType sh command! RB :!bash %
au FileType javascript command! RJs :!node %
au FileType go command! RGo :!go run %
au FileType php command! RPHP :!php %
nnoremap <F12> :call CodeRunner()<CR>
augroup end
With this, you can run bash, python, javascript, golang and php with the F12 key.
A better idea
While the above script works, it goes without saying that it's a mess, we can improve it by using a dictionary and checking the ft variable against it.
function! CodeRunner()
silent !clear
let file_commands = {
\ 'python': 'python3',
\ 'sh': 'bash',
\ 'javascript': 'node',
\ 'go': 'go run',
\ 'php': 'php',
\ 'perl': 'perl'
\ }
let ft = &filetype
if has_key(file_commands, ft)
let cmd = file_commands[ft]
execute '!' . cmd . ' %'
else
echo "No run command defined for filetype: " . ft
endif
endfunction
command! CodeRunner call CodeRunner()
nnoremap <F12> :CodeRunner<CR>
A similar method can be used for compiled languages, such as C.
Example:
function! CompileAndRun()
let current_file = expand('%')
let file_name = fnamemodify(current_file, ':t:r')
let compile_cmd = 'gcc ' . current_file . ' -o ' . file_name . ' && ./' . file_name
execute '!'.compile_cmd
endfunction
The function above, will compile the C code inside the current buffer using gcc, and then execute the binary output.
Naturally, we need a corresponding mapping:
nnoremap <F8> :call CompileAndRun()<CR>
More arguments can be added to the compile _cmd to serve your needs.
Update
You can improve the CodeRunner and CompileAndRun functions by converting them to vim9script.
vim9script
def CodeRunner()
var file_commands = {
'python': 'python3',
'sh': 'bash',
'javascript': 'node',
'go': 'go run',
'php': 'php',
'perl': 'perl',
}
# filetype variable
var ft = &filetype
# check if ft is found in the dict
if has_key(file_commands, ft)
var cmd = file_commands[ft]
silent !clear
execute '!' .. cmd .. ' %'
else
echo "No run command defined for filetype: " .. ft
endif
enddef
# compile the functions
defcompile
command! CodeRunner call CodeRunner()
nnoremap <F12> :CodeRunner<CR>
We can also improve our CompileAndRun function to display the compiler errors, which is something that we could've done in legacy vim9script as well, but oh well ...
# Compile and Run with Error Split
def CompileAndRun()
var current_file = expand('%')
var file_name = fnamemodify(current_file, ':t:r')
var compile_cmd = 'gcc ' .. current_file .. ' -o ' .. file_name
# Compile
var compile_result = systemlist(compile_cmd)
# If there are errors
if v:shell_error != 0
botright new +setlocal\ buftype=nofile\ bufhidden=wipe\ noswapfile
file CompileErrors
call setline(1, compile_result)
return
endif
# Run binary
execute 'terminal ./' .. file_name
enddef
defcompile
I think the comments are enough to let you know what is going on. It simply compiles and executes the binary while showing the results in a split, and if there are errors, it simply displays them in a split.
You can also set this up to automatically close the error split when you switch back to your code.
# Global variable to set if error split is closed automatically
g:compile_err_auto_close = 0
# Augroup to automatically close the error split
if g:compile_err_auto_close == 1
augroup AutoCloseCompileErrors
autocmd!
autocmd! BufEnter * if bufname('CompileErrors') != '' | execute 'bdelete! CompileErrors' | endif
augroup END
endif
Note
You only need to write defcompile
once at the end of your script to compile all the functions in that file. So if you plan to put these functions in one vimscript file, you only need one defcompile
entry for both of them.
Note Two
For a more complete and in depth script with an improved CompileAndRun function in Vim9Script, see my other article. How to write vim9script or How to Compile and Run C code from Vim