How to execute file I'm editing in Vi(m) - vim

How to execute file that I'm editing in Vi(m) and get output in split window (like in SciTE)?
Of course I could execute it like that:
:!scriptname
But is it posible to avoid writing script name and how to get output in split window instead just bottom of the screen?

There is the make command. It runs the command set in the makeprg option. Use % as a placeholder for the current file name. For example, if you were editing a python script:
:set makeprg=python\ %
Yes, you need to escape the space. After this you can simply run:
:make
If you wish, you can set the autowrite option and it will save automatically before running the makeprg:
:set autowrite
This solves the execute part. Don't know any way of getting that output into a split window that doesn't involve redirection to file.

To access the current buffer's filename, use %. To get it into a variable you can use the expand() function. To open a new window with a new buffer, use :new or :vnew. To pipe the output from a command into the current buffer, use :.! . Putting it all together:
:let f=expand("%")|vnew|execute '.!ruby "' . f . '"'
obviously replacing ruby with whatever command you want. I used execute so I could surround the filename with quotation marks, so it'll work if the filename has spaces in it.

Vim has ! ("bang") command which executes shell command directly from VIM window. Moreover it allows launching sequence of commands that are connected with pipe and read stdout.
For example:
! node %
is equivalent to opening command prompt window and launching commands:
cd my_current_directory
node my_current_file
See "Vim tips: Working with external commands" for details.

I have a shortcut for that in my vimrc:
nmap <F6> :w<CR>:silent !chmod 755 %<CR>:silent !./% > .tmp.xyz<CR>
\ :tabnew<CR>:r .tmp.xyz<CR>:silent !rm .tmp.xyz<CR>:redraw!<CR>
This writes the current buffer, makes the current file executable (unix only), executes it (unix only) and redirects the output to .tmp.xyz, then creates a new tab, reads the file and then deletes it.
Breaking it down:
:w<CR> write current buffer
:silent !chmod 755 %<CR> make file executable
:silent !./% > .tmp.xyz<CR> execute file, redirect output
:tabnew<CR> new tab
:r .tmp.xyz<CR> read file in new tab
:silent !rm .tmp.xyz<CR> remove file
:redraw!<CR> in terminal mode, vim get scrambled
this fixes it

For Shell script I've used
:set makeprg=%
:make

Vim 8 has an interactive terminal built in. To run the current bash script in a split pane:
:terminal bash %
or for short
:ter bash %
% expands to the current file name.
From :help terminal:
The terminal feature is optional, use this to check if your Vim has it:
echo has('terminal')
If the result is "1" you have it.

I use a slightly more intrusive mechanism through maps:
map ;e :w<CR>:exe ":!python " . getreg("%") . "" <CR>
Just makes it so I don't have to save, then go. Just go.

You can use vim's plugin bexec. To my knowledge the latest version is 0.5.
Then:
$ mkdir -p ~/.vim/plugin
$ mv bexec-0.5.vba ~/.vim/plugin
$ vim ~/.vim/plugin/bexec-0.5.vba
Inside vim itself while editing the .vba file do:
:so %
Some output will show up letting you know that bexec.vim has been written as well as documentation, etc..
Now, you can test it by opening your (whatever language script that has an #! interpreter working properly) in vim and run
:Bexec
Note: I wanted the split to be vertical rather than horizontal, so I did:
$ grep -i -n split ~/.vim/plugin/bexec.vim | grep -i hor
102: let bexec_splitdir = "hor" " hor|ver
261: exec {"ver":"vsp", "hor":"sp"}[g:bexec_splitdir]
and changed the value of from "hor" to "ver"..
I know it's an old question, but I hope this can help someone out there. I have been running in the same issue while taking Coursera's Startup Engineering course where professor Palaji uses Emacs and I don't like Emacs..

Just use colon and exclamatory mark as shown below
:!< script_name>

Based on #SethKriticos and #Cyril answers I now use the following:
function! Setup_ExecNDisplay()
execute "w"
execute "silent !chmod +x %:p"
let n=expand('%:t')
execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
" I prefer vsplit
"execute "split ~/.vim/output_".n
execute "vsplit ~/.vim/output_".n
execute "redraw!"
set autoread
endfunction
function! ExecNDisplay()
execute "w"
let n=expand('%:t')
execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
" I use set autoread
"execute "1 . 'wincmd e'"
endfunction
:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>
Use F9 to setup the new window and F2 to execute your script and tee to your output file.
I also added the script name to the output file name, so that you can use this for multiple scripts at the same time.

In your .vimrc you can paste this function
function! s:ExecuteInShell(command)
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute ':w'
silent! execute winnr < 0 ? 'vnew ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
silent! execute 'silent %!'. command
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
silent! execute 'wincmd w'
" echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
cabbrev shell Shell
After that, in vim run command :shell python ~/p.py as example. And you will get the output in splitted window.
+ After changes in p.py as example you will run the same command again, this function will not create new window again, it will display the result in the previous(same) splitted window.

#xorpaul
I was looking for this script (python/Windows) for quite some time. As there is no "tee" in Windows I changed it to:
function! Setup_ExecNDisplay()
execute "w"
let n=expand('%:t')
execute "silent ! python % > d:\\temp\\output_".n ." 2>&1"
execute "vsplit d:\\temp\\output_".n
execute "redraw!"
set autoread
endfunction
function! ExecNDisplay()
execute "w"
let n=expand('%:t')
execute "silent ! python % > d:\\temp\\output_".n . " 2>&1"
endfunction
:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>

I'd recommend the plugin quickrun. It's fast and simple to configure. Here's a little demonstration:

Related

How do I automatically re-load a file that gets modified by a bang (!) commandin Vim?

I have set up a line of vimscript in my .vimrc file to pretty print JavaScript files:
nnoremap <leader>p :!js-beautify -r -j %<cr>
I want to just automatically reload the file instead of being prompted when vim comes back from the shell, is that possible? Thanks.
:! can be used a) to execute arbitrary shell commands or b) as a filter.
You are using it to run js-beautify against the file associated with the current buffer with the following consequences:
You are forced to exit Vim.
The file is modified outside of Vim so you get a prompt asking you if you want to reload or not.
Hence the many seemingly pointless <CR>.
What you actually want is to run js-beautify as a filter against the current buffer, which doesn't require you to exit Vim or press <CR>:
nnoremap <leader>p :%!js-beautify -f - -j<cr>
the special range % represents the whole buffer, it's the range on which we want to apply our filter
-f - passes the content of the buffer via stdin
That's it: no <CR>, no prompt, no mess.
As a bonus, here is a custom command from my config (I didn't want a mapping for that):
command! -buffer -range=% Format execute <line1> . "," . <line2> . "!js-beautify -f - -j -B -s " . &shiftwidth
edit
You can use context marks to return the cursor to its initial position:
nnoremap <leader>p m`:%!js-beautify -f - -j<CR>``
As the help for :! notes:
Vim redraws the screen after the command is finished,
because it may have printed any text. This requires a
hit-enter prompt, so that you can read any messages.
To avoid this use:
:silent !{cmd}
The screen is not redrawn then, thus you have to use
CTRL-L or ":redraw!" if the command did display
something.
So if you wanted to use the :redraw! approach, for example, you could do this using something like
nnoremap <leader>p :silent !js-beautify -r -j %<cr>:e!<cr>:redraw!<cr>

Vim: open a temporary buffer displaying executable's output

I have found the :cwindow command to be very useful and I was wondering if I could get similar functionality using the output of my compiled code. I'd the output of :!./a.out to appear in a "quickfix" style buffer.
I've also noticed that even after taking the standard steps to prevent the "Press Enter to continue" message, it still happens at least once on :make and :!./a.out - using :silent to suppress this causes my tmux to go completely blank. My current workaround involves a mapping with a lot of carriage returns, is there another way?
Sure, you can use vim's preview window with a short function to execute the command, try this in your .vimrc:
fun! Runcmd(cmd)
silent! exe "noautocmd botright pedit ".a:cmd
noautocmd wincmd P
set buftype=nofile
exe "noautocmd r! ".a:cmd
noautocmd wincmd p
endfun
com! -nargs=1 Runcmd :call Runcmd("<args>")
Then you can:
:Runcmd ls
And see the results of ls in your preview window
I found this:
" Shell ------------------------------------------------------------------- {{{
function! s:ExecuteInShell(command) " {{{
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute winnr < 0 ? 'botright vnew ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap nonumber
echo 'Execute ' . command . '...'
silent! execute 'silent %!'. command
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>:AnsiEsc<CR>'
silent! execute 'nnoremap <silent> <buffer> q :q<CR>'
silent! execute 'AnsiEsc'
echo 'Shell command ' . command . ' executed.'
endfunction " }}}
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
nnoremap <leader>! :Shell
" }}}
in steve losh's .vimrc - see which I shamelessly copied.
I have just discovered the :read command, which puts the output of a shell command into a window.
I went looking for this because I often want to grep for a file in the current directory which contains a certain string (and then open it into my current VIM).
Here is a shortcut I have in my $MYVIMRC:
noremap <leader>g :new<CR>:read ! grep -rn "
With this, when I press \g I get a new buffer created in a split window and find
:read ! grep -rn "
sitting waiting for me in the command area. Now I just type my search string, close the double quotes and hit <Enter> and the buffer fills with the command output.
Once done, a simple
:bw!
in that new buffer will kill it.
First open a preview window, and set it to autoread a file:
:botr pedit +:setl\ autoread /tmp/out.log
Now just run your command, and send the output to the file.
:!date > /tmp/out.log 2>&1
The result of your command should appear in the preview window.
However, we are still getting the "Press ENTER" prompt. A simple way to avoid that is to make a mapping that presses Enter for us:
:nmap <Leader>r :exec '!date > /tmp/out.log 2>&1'<CR><CR><CR>
I thought only two <CR>s would be needed but then found myself needing three.

How to redirect stdout output to a new Vim tab?

I'm editing an XML file in Vim, and then I want to transform it a plain-text file with xsltproc, which by default outputs to a stdout (something like : !xsltproc TXTRULE.XSL %). Is it possible to redirect that xsltproc output to a new tab in Vim without creating any intermediate files?
(I've tried to read :help redir and some wiki notes, but still can't get it. would be greateful for some kind of simple example.)
You can use read like in the following:
:read !ls
Obviously you should change ls with your command. If you want to open a new tab prepend tabnew with a bar to the command like:
:tabnew|read !ls
To expand on lucapette's answer, you could create a map like this:
:map ,x :tabnew<Bar>read !xsltproc TXTRULE.XSL #
# expands to the previously opened buffer, which is the file you were editing, while % would expand to the new buffer opened by :tabnew.
<Bar> has to be used instead of |, because otherwise, the :map command would end at the |.
I am using the following to view my program outputs (very useful for a makefile with a make run rule)
It opens a new tab next to current one only if one was not already opened before for that purpose:
fu! RedirStdoutNewTabSingle(cmd)
let a:newt= expand('%:p') . ".out.tmp"
tabnext
if expand('%:p') != a:newt
tabprevious
exec "tabnew" . a:newt
else
exec "%d"
endif
exec 'silent r !' . a:cmd
set nomodified
endfunc
au FileType xml noremap <buffer> <F6> :call RedirStdoutNewTabSingle("xsltproc")<CR>

Execute a script directly within vim/mvim/gvim

TextMate has a nice feature that allows you to execute a script from within the current context and shows you the output in a separate window. This lets you write and test code on the go. I'm almost certain there is a similar feature with MacVim/gVIM, but I'm not sure what it is. Currently I save my buffers to disk, then go to the command line and execute the script in that respect. How do I improve that workflow with vim?
You can do this in vim using the ! command. For instance to count the number of words in the current file you can do:
:! wc %
The % is replaced by the current filename. To run a script you could call the interpreter on the file - for instance if you are writing a perl script:
:! perl %
vim tutorial: Mapping keys in Vim
You can map keys so perl executes current script as suggested by jts above.
map <C-p> :w<CR>:!perl %<CR>
will map Ctrl+P to write file and run it by perl
imap <C-p> <Esc>:w<CR>:!perl %<CR>
lets you call the same in insert mode.
You should have .vimrc (_vimrc for Windows) file in your vim/home folder. It has instructions on how vim should behave.
map <C-p> :w<CR>:!perl %<CR> is just instruction to map Ctrl+p to:
a) write current the file :w
b) run command (perl) using % (currently open file) as parameter :!perl %
<CR> after each command stands for "carriage return": an instruction to execute specific command. imap does the same as map but listens Ctrl+p while in insert mode.
You could run it right from vim:
:!./script.sh
All suggestions here merely showcased :!{cmd} %, which passes current buffer to the shell cmd.
But there is another option :write !{cmd}
For example, the effect of the :write !sh command is that each line of the current buffer is executed in the shell.It is often useful, when for instance you've added a couple of lines to you buffer, and want to see execution result immediately without saving the buffer first.Also it is possible to execute some range, rather than whole content of the buffer::[range]write !{cmd}
save the file and call the script using an interpreter
eg.:
:!python %
It sounds like you're looking for !:
:!{cmd} Execute {cmd} with the shell.
You can use % to denote the current filename, if you need to pass it to the script:
!proofread-script %
You can also use ! with a range, to use the command as a filter:
!{motion}{filter} " from normal mode
:{range}!{filter} " from command mode
(In the first case, as with many other commands, when you type the motion, it'll pass you into command mode, converting the motion into a range, e.g. :.,.+2!)
And finally, if you don't actually need to pass input from your file, but want the output in your file, that's essentially a trivial filter, and the fastest way to do it is !!{cmd}. This will replace the current line with the output of the command.
To execute the current executable script, use
:!./%
! executes a shell command, % is the current filename and ./ adds the current dir in front.
Put this small snippet in your .vimrc to execute the current file with one keystroke (like F5) and display the result in a new split-pane buffer.
:! is okay but you need to switch to your terminal to see the result.
While you can do that with ctrl-z and bring vim back with fg it still means you need to switch context a lot.
The way this snippet works is by first guessing the executable based on the filetype and then running it with the current file as its argument.
Next a handy utility method takes the output and dumps it into a new buffer.
It's not perfect, but really fast for common workflows.
Here's the snippet copied below:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"""""""""""""""""""""""""" RUN CURRENT FILE """""""""""""""""""""""""""""
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Execute current file
nnoremap <F5> :call ExecuteFile()<CR>
" Will attempt to execute the current file based on the `&filetype`
" You need to manually map the filetypes you use most commonly to the
" correct shell command.
function! ExecuteFile()
let filetype_to_command = {
\ 'javascript': 'node',
\ 'coffee': 'coffee',
\ 'python': 'python',
\ 'html': 'open',
\ 'sh': 'sh'
\ }
let cmd = get(filetype_to_command, &filetype, &filetype)
call RunShellCommand(cmd." %s")
endfunction
" Enter any shell command and have the output appear in a new buffer
" For example, to word count the current file:
"
" :Shell wc %s
"
" Thanks to: http://vim.wikia.com/wiki/Display_output_of_shell_commands_in_new_window
command! -complete=shellcmd -nargs=+ Shell call RunShellCommand(<q-args>)
function! RunShellCommand(cmdline)
echo a:cmdline
let expanded_cmdline = a:cmdline
for part in split(a:cmdline, ' ')
if part[0] =~ '\v[%#<]'
let expanded_part = fnameescape(expand(part))
let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '')
endif
endfor
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded Form: ' .expanded_cmdline)
call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. expanded_cmdline
setlocal nomodifiable
1
endfunction
Well it depends on your OS - actually I did not test it on M$ Window$ - but Conque is one of the best plugins around there: http://code.google.com/p/conque/
Actually, it can be better, but works. You can embed a shell window in a vim "window".

Adding a command to Vim

I finally decided to try out Vim, as I am getting increasingly frustrated by GUI editors. So far, I'm loving it, but I can't find any help for a issue I'm having...
I am trying to map the command :Pyrun to :!python % in Vim using cmap. The mapping shows up fine if I type :cmap. However, on typing :Pyrun, I get this error message:
Not an editor command: Pyrun.
Here is what I'm trying in .vimrc:
:autocmd FileType python :cmap Pyrun<cr> !python %<cr>
:autocmd FileType python :cmap Intpyrun<cr> !python -i %<cr>
What can I do to solve this problem?
I would try something like this in your .vimrc or your ftplugin/python_ft.vim
command Pyrun execute "!python %"
command Intpyrun execute "!python -i %"
Then :Pyrun and :Intpyrun should work
You could then map a function key to each
map <F5> :Pyrun<CR>
map <F6> :Intpyrun<CR>
I personally prefer another approach. First create a function receiving the command arguments and then create a command to call the function:
fun! DoSomething( arg ) "{{{
echo a:arg
" Do something with your arg here
endfunction "}}}
command! -nargs=* Meh call DoSomething( '<args>' )
So it would be like
fun! Pyrun( arg ) "{{{
execute '!python ' . expand( '%' )
endfunction "}}}
command! -nargs=* Pyrun call Pyrun( '<args>' )
But, there's a better way to do it in Vim. Use makeprg:
makeprg=python\ %
Just type :make to run your current Python file. Use :copen to show error list.
G'day,
Similar to karoberts answer, I prefer the more direct:
:map <F9> :!python %<CR>
If my script is creating some output I also like to capture it in a temp file and then autoread that files content into another buffer, e.g.
:map <F9> :!python % 2>&1 \| tee /tmp/results
I then set autoread by entering :set autoread and opening the results file in another buffer
:split /tmp/results<CR>
Then I can easily see the results of the run in the buffer that auto refreshes when the results file is updated by running the script under development.
HTH
cheers,
With new LUA api:
vim.api.nvim_create_user_command('Hello', 'echo "Hello World!"', {})
vim.api.nvim_create_user_command('HelloLua', function ()
print('Hello LUA!')
end, {})
NeoVIM API reference

Resources