54

I do a lot of Python quick simulation stuff and I'm constantly saving (:w) and then running (:!!). Is there a way to combine these actions?

Maybe a "save and run" command.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nope
  • 34,682
  • 42
  • 94
  • 119

12 Answers12

86

Okay, the simplest form of what you're looking for is the pipe command. It allows you to run multiple cmdline commands on the same line. In your case, the two commands are write `w` and execute current file `! %:p`. If you have a specific command you run for you current file, the second command becomes, e.g. `!python %:p`. So, the simplest answer to you question becomes:

:w | ! %:p
 ^ ^ ^
 | | |--Execute current file
 | |--Chain two commands
 |--Save current file

One last thing to note is that not all commands can be chained. According to the Vim docs, certain commands accept a pipe as an argument, and thus break the chain...

Douglas Mayle
  • 21,063
  • 9
  • 42
  • 57
  • 3
    All in one command. This is the answer I would look for, not scripting or mapping. I wasn't aware of the `|` being used to chain commands. Thx! – dwerner Nov 05 '13 at 18:21
31

Option 1:

Write a function similar to this and place it in your startup settings:

function myex()
   execute ':w'
   execute ':!!'
endfunction

You could even map a key combination to it -- look at the documentation.


Option 2 (better):

Look at the documentation for remapping keystrokes - you may be able to accomplish it through a simple key remap. The following works, but has "filename.py" hardcoded. Perhaps you can dig in and figure out how to replace that with the current file?

:map <F2> <Esc>:w<CR>:!filename.py<CR>

After mapping that, you can just press F2 in command mode.

imap, vmap, etc... are mappings in different modes. The above only applies to command mode. The following should work in insert mode also:

:imap <F2> <Esc>:w<CR>:!filename.py<CR>a

Section 40.1 of the Vim manual is very helpful.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gahooa
  • 131,293
  • 12
  • 98
  • 101
18

Use the autowrite option:

:set autowrite

Write the contents of the file, if it has been modified, on each :next, :rewind, :last, :first, :previous, :stop, :suspend, :tag, :!, :make, CTRL-] and CTRL-^ command [...]

strager
  • 88,763
  • 26
  • 134
  • 176
7

Here you go:

:nmap <F1> :w<cr>:!%<cr>

Save and run (you have to be in n mode though - just add esc and a for i mode).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rook
  • 60,248
  • 49
  • 165
  • 242
  • for python scripts with x bit set and `#!/bin/bash/env python` as the first line, `map :w :!./%` in $HOME/.vimrc works fine. (map or nmap, F1 or others). – lllluuukke Jan 06 '13 at 23:18
5

Command combination seems to work through the | character, so perhaps something like aliasing :w|!your-command-here to a distinct key combination.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dimitri Tcaciuc
  • 5,053
  • 5
  • 20
  • 22
4

In Vim, you could simply redirect any range of your current buffer to an external command (be it Bash, the Python interpreter, or you own Python script).

# Redirect whole buffer to 'python'
:%w !python

Suppose your current buffer contains two lines as below,

import numpy as np
print np.arange(12).reshape(3, 4)

then :%w !python will run it, be it saved or not. And print something like below on your terminal,

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Of course, you could make something persistent, for example, some keymaps.

nnoremap <F8> :.w !python<CR>
vnoremap <F8> :w !python<CR>

The first one, run the current line. The second one, run the visual selection, via the Python interpreter.

#!! Be careful, in Vim ':w!python' and ':.w !python' are very different. The
first write (create or overwrite) a file named 'python' with contents of
current buffer, and the second redirects the selected cmdline range (here dot .,
which mean current line) to external command (here 'python').

For cmdline range, see

:h cmdline-ranges

Not the below one, which concerning normal command, not cmdline one.

:h command-range

This was inspired by Execute current line in Bash from Vim.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
qeatzy
  • 1,363
  • 14
  • 21
  • Actually, this answer is more IDE alike answer. Modern IDEs won't save the file before 'run'. I upvote this one. – minion Nov 15 '16 at 16:04
4

Another possibility:

au BufWriteCmd *.py write | !!

Though this will run every time you save, which might not be what you want.

0x89
  • 2,940
  • 2
  • 31
  • 30
2

This is what I put in my .vimrc file and works like a charm:

nnoremap <leader>r :w<CR>:!!<CR>

Of course you need to run your shell command once before this, so it knows what command to execute.

Example:

:!node ./test.js
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Cory
  • 10,635
  • 10
  • 52
  • 62
1

I got the following from the Vim tips wiki:

command! -complete=file -nargs=+ shell call s:runshellcommand(<q-args>)
function! s:runshellcommand(cmdline)
  botright vnew
  setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
  call setline(1,a:cmdline)
  call setline(2,substitute(a:cmdline,'.','=','g'))
  execute 'silent $read !'.escape(a:cmdline,'%#')
  setlocal nomodifiable
  1
endfunction

But I changed new to vnew on the third line, and then for Python I have the following:

map <F9> :w:Shell python %<cr><c-w>

Hitting F9 saves, runs, and dumps the output into a new vertically split scratch buffer, for easy yanking, saving, etc. It also hits c-w so I only have to press h/c to close it and move back to my code.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sjh
  • 2,236
  • 1
  • 18
  • 21
0

Try making it inside the Bash.

In case of a C file called t.c, this is very convenient:

vi t.c &&  cc t.c -o t && ./t

The and symbols (&&) ensure that one error message breaks the command chain.

For Python this might be even easier:

vi t.py && python t.py
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
0

This will work in insert mode too:

" F5 => Save & Run python3 "
nnoremap <F5> :w <CR> :!sh -c 'python3 %' <CR>
inoremap <F5> <Esc> :w <CR> :!sh -c 'python3 %' <CR>

I use it all the time to test stuff that is just too long to retype in the interpreter.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-13
  1. Consider switching to IDLE. F5 does everything.

  2. Consider switching to Komodo IDE. You can define a command so that F5 does everything.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
S.Lott
  • 384,516
  • 81
  • 508
  • 779