I have in .vimrc:
function! s:Edit(path)
vsplit a:path
endfunction
command! -nargs=1 -complete=file E call s:Edit(<q-args>)
Problem is that in new window i have file named "a:path" not file passed as argument to :E command.
Although my function starts to work when i do:
exec "vsplit".a:path
Why?
Can it be done better?
Build up your command and execute it with :execute. e.g.
function! s:Edit(path)
execute 'vsplit ' . a:path
endfunction
command! -nargs=1 -complete=file E call s:Edit(<q-args>)
For more help see :h :exe
Is there a better way?
Really depends on your goals. I would need more information about what this is supposed to do. However it seem like you want to create an alias for :vsplit. I would suggest you using cmdalias.vim or a the very least the following:
command! -nargs=? -complete=file -bang E vsplit<bang> <args>
If all you are doing is trying to optimize key strokes then the following mapping would also be sufficient:
nnoremap <leader>v :vsp<space>
Personally I would just get used to using :vsplit and stop worrying.
I like using code cleanup scripts; perldidy; uglifierjs, etc. I previously ran them all like this in my vimrc...
map <leader>pt :!perltidy<CR>
map <leader>jt :!uglifyjs -b<CR>
map <leader>pjt :!python -mjson.tool<CR>
map <leader>ct :!column -t<CR>
How this functionally works; it runs currently selected text throguh the CLI program, and replaces the selection with the output. Works wonderfully; but as you can see I now have to stop and think what beautifier I want to run and remember the nemonic I have for it. This led me to think there has to be a better way. So I tried did this...
map <leader>jt :call RunTidy()<cr>
function! RunTidy()
if (&ft == "javascript")
echo 'is js..'
:'<,'>!ulifyjs -b
endif
if (&ft == "json")
echo 'is json'
:'<,'>!python -mjson.tool
endif
endfunction
The problem being this just doesn't work; executing once for each line and not replacing contents.. Anyone aware of a better way to do this? I feel like this should be a solved problem...
augroup filters
autocmd!
autocmd FileType perl map <buffer> <leader>t :!perltidy<CR>
autocmd FileType javascript map <buffer> <leader>t :!uglifyjs -b<CR>
autocmd FileType json map <buffer> <leader>t :!python -mjson.tool<CR>
augroup END
or put those mappings, all with the same lhs, in different ~/.vim/after/ftplugin/{filetype}.vim.
Use ftplugins. You need to have filetype plugin indent on in your vimrc.
Create files in ~/.vim/ftplugin/<filetype>.vim. These files will be sourced when the file type is set.
For example using javascript put the following in ~/.vim/ftplugin/javascript.vim
noremap <buffer> <leader>jt :!uglifyjs -b<CR>
to map <leader>jt to :!uglifyjs -b<CR> in all javascript buffers. This will not show up in other filetypes.
You would do the same for all other filetypes.
You can do the same for file type specific settings by using setlocal.
Take a look at :h ftplugin
How could I map a command to save the current file and then run it?
I am trying this:
:nnoremap <leader>r :w<CR>| !python %
This runs the python command instantly but not when I call the leader key. What am I missing here?
Just to follow up on what Conner was saying, you can do something like this:
nnoremap <leader>r :w \| !python %<cr>
Aha, I don't need the pipe character when writing a map, just a second colon:
:nnoremap <leader>r :w<CR> :!python % <CR>
Within VIM, I can execute Octave scripts via this mapping:
map <F6> :w<CR>:!run-octave -q % <CR>
However, as I recently discovered, Octave doesn't show any plots unless there is a "pause" command at the end of a script.
How can I map F6 so this pause command is added automatically each time I invoke the key?
Thanks.
This may not be the best way to handle running Octave scripts from Vim, see below for an alternative.
The requested solution
To accomplish what you want, define the following function somewhere:
function! RunOctave()
let save_cursor = getpos('.')
call append(line('$'), "pause")
write
execute "!run-octave -q " . expand('%')
$delete _
write
call setpos('.', save_cursor)
endfunction
And define a mapping to call it:
map <F6> :w<CR>:call RunOctave<CR>
A better approach
I started out by running Octave similar to the above, but as I tend to use slow computers this is not a good solution for me. I have instead configured Vim to remote-control an instance of Octave.
This can be done through a terminal multiplexer, similar to what I suggested for Matlab here, e.g.:
tmux new-session -s octave "octave -q"
For optimal flexibility, I want to be able to evaluate single lines in octave from Vim:
imap <buffer> <F1> <Esc>:!tmux send-keys -t octave "<C-r>=getline('.')<CR>"<C-r>=nr2char(13)<CR><CR>a
nmap <buffer> <F1> :!tmux send-keys -t octave "<C-r>=getline('.')<CR>"<C-r>=nr2char(13)<CR><CR>
Evaluate visual selections:
vmap <buffer> <F2> call ExecSelection()<CR><CR>
Which depends on the following function:
let s:octave_selection = '/var/tmp/vim_octave_selection.m'
function! ExecSelection()
if line(".") == line("'<'")
exec ".write! " . s:octave_selection
else
exec ".write! >> " . s:octave_selection
endif
if line(".") == line("'>")
exec "!tmux send-keys -t octave 'run " . s:octave_selection . "'" . nr2char(13)
endif
endfunction
And last, but not least, evaluate the whole file:
imap <buffer> <F3> <Esc>:!tmux send-keys -t octave "<C-r>=expand('%:t:r')<CR>"<C-r>=nr2char(13)<CR><CR>a
nmap <buffer> <F3> :!tmux send-keys -t octave "<C-r>=expand('%:t:r')<CR>"<C-r>=nr2char(13)<CR><CR>
This last mapping requires that the current working directory for the buffer is the same as that of the Octave script.
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: