52

I waste a lot of time between Vim and Python. I find it too slow to manually copy-paste from Python to Vim and vice versa. A good broken example is:

%!python for i in xrange(25); print 6*i \n

How can you do such tweaks direcly in Vim? [Solved]

[Clarification] I need things to Vim, like printing sequences, arithmetics... - things I cannot do in Vim.

[?] Can someone elaborate this point: "your script can read from stdin to operate directly on the lines given (., %, ...)."

[Further Clarification]

If I want to print 'Hello' to lines 4,5, 6 and 7, what is wrong:

:4-7!python -c "print 'hello'"

The dot . modifies the current line. Can I print on multiple lines 7, 32 and 99:

:7,32,99!python -c "print 'hello'"

Clearly not working. How?

Léo Léopold Hertz 준영
  • 134,464
  • 179
  • 445
  • 697

12 Answers12

165

In any of your vim windows, type something like this:

for x in range(1,10):
    print '-> %d' % x

Visually select both of those lines (V to start visual mode), and type the following:

:!python

Because you pressed ':' in visual mode, that will end up looking like:

:'<,'>!python

Hit enter and the selection is replaced by the output of the print statements. You could easily turn it into a mapping:

:vnoremap <f5> :!python<CR>
too much php
  • 88,666
  • 34
  • 128
  • 138
  • 12
    I've been using vim and python for years and yet this suggestion just blew my mind. No idea why that never occurred to me. – rhettg Feb 01 '09 at 22:46
  • 3
    Actually I didn't realize it could be done so easily until HL asked his question and I had to figure out an answer ... – too much php Feb 03 '09 at 22:50
  • Type "ggVG" in normal mode to visually select all. Or, if, like me, you use MacVim, it's just command-a. – AlcubierreDrive Dec 03 '11 at 04:26
  • Amazingly simple and astoundingly useful. I've only been playing with this for a few minutes but what a fabulous way to handle generating a series of almost identical statements with programmatic substitutions. One of the neatest aspects is using vim's undo to retrieve and edit the python code if the first try doesn't work as expected. – Mike Ellis Jan 19 '12 at 21:07
  • 7
    OMG. Just realized this trick will work with anything that writes to stdout, e.g. `ls -l` then select Visual and run with `:'<,'>!bash` – Mike Ellis Jan 19 '12 at 21:49
  • 1
    Position cursor on the begining of a definition and type "V}!python" to send the selected paragraph to python. – BandGap Jun 06 '12 at 09:55
  • The real good thing about this is it canbe used with any scripting language, try **print('Hello '..'World')** with !lua – FUD Feb 01 '13 at 10:51
6

Can someone elaborate this point: "your script can read from stdin to operate directly on the lines given (., %, ...)."

One common use is to sort lines of text using the 'sort' command available in your shell. For example, you can sort the whole file using this command:

:%!sort

Or, you could sort just a few lines by selecting them in visual mode and then typing:

:!sort

You could sort lines 5-10 using this command:

:5,10!sort

You could write your own command-line script (presuming you know how to do that) which reverses lines of text. It works like this:

bash$ myreverse 'hello world!'
!dlrow olleh

You could apply it to one of your open files in vim in exactly the same way you used sort:

:%!myreverse      <- all lines in your file are reversed
too much php
  • 88,666
  • 34
  • 128
  • 138
5

From your example, it appears as though you want to execute a Python script and have the output of the script appear in the current Vim buffer. If that's correct, then you can do the following at the command line in Vim:

%!python -c "for i in xrange(25): print 6*i"

The -c option to python gives it a script to run. However, you may find this technique useful only in very short cases, because unlike some other languages, Python does not lend itself well to writing complete programs all on one line.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

I just wrote the following module that lets you edit a temporary buffer in vim directly in the Python interpreter.

http://philipbjorge.github.com/EditREPL/

1

if you have written your python script in a new [No Name] buffer, then you can use following:

:0,$!python

when you have a no name buffer then you can not use '%', hence the need for 0,$ which means all lines in buffer starting with line zero until the last line

output will be written in buffer and unfortunately not at the end

serup
  • 3,676
  • 2
  • 30
  • 34
1

You can execute the code, read the output on the cursor and finish with u, supposing you are executing python code. Simple and quick.

:r !python %

u

I like it over mapping and selecting-in-visual-mode, like with too-much-php, because it keeps the base simple!

Community
  • 1
  • 1
hhh
  • 50,788
  • 62
  • 179
  • 282
  • this however is not possible if you are using a tmp buffer - you have to save it first, then it works - any chance you know how to make this work for a tempory buffer? – serup Dec 09 '16 at 11:00
1

I think you't just missing the -c flag. For example:

:.!python -c "print 'hello'"

You should not that the script that you provide acts as a filter on the line selection. That is, your script can read from stdin to operate directly on the lines given (., %, ...). Anything more than the simplest tasks, however, and you'd be better off putting the python commands into a script file of its own.

Martin Carpenter
  • 5,893
  • 1
  • 28
  • 32
0

On Windows, if you are editing the python script, just do:

!start python my...

and press tab to cycle along the available file names, until you find your match:

!start python myscript.py

It will run in a new cmd window. Personally I prefer to do !start cmd and from there run Python, since it is easier to debug from the eventual error messages.

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
0

If I want to print 'Hello' to lines 4,5, 6 and 7, what is wrong:

If you want to do something in randomly chosen places throughout your file, you're better of recording keystrokes and replaying them. Go to the first line you want to change, and hit qz to starting recording into register z. Do whatever edits you want for that line and hit q again when you're finished. Go to the next line you want to change and press @z to replay the macro.

too much php
  • 88,666
  • 34
  • 128
  • 138
0

If you want to do some python calls without compiling vim with the python interpreter (that would allow you to write plug-ins in Python, and it's also needed for Omnicomplete anyway) you can try as this:

:.!python -c "import os; print os.getcwd()"

That would tell you where you are in the drive (current path).

Now let's number a few lines, starting from an empty file so we can see the result easily:

:.!python -c "for i in range(1,101): print i"

(vim numbers lines from 1 not 0) Now we have just the number of each line in every line up to line 100.

Let's now put a small script in your current path (as shown above) and run it, see how it works. Let's copy paste this silly one. In reality you will find most useful to do script that output one line per line, but you don't have to do that as this script shows:

print "hi"

try:
    while True:
        i=raw_input()
        print "this was:",i
except EOFError:
    print "bye"

So you can call, for instance (imagine you called it "what.py"):

:10,20!python what.py

(Note that tab completion of file names works, so you can verify it's actually in the path)

As you can see, everyline is fed to the script as standard input. First it outputs "hi", at the end "bye" and in between, for each line you output "this was: " plus the line. This way you can process line-by-line. Notice you can do more complex stuff than processing line by line, you can actually consider previous lines. For such stuff I'd rather import sys and do it like this:

import sys

print "hello"

for i in sys.stdin.readlines():
    i = i.rstrip("\n") # you can also prevent print from doing \n instead
    print "here lyeth",i

print "see you"

Hope that helps.

nachik
  • 754
  • 3
  • 9
  • 11
0

I think what you really want is explained here.

André
  • 12,971
  • 3
  • 33
  • 45