tags:

views:

1993

answers:

8

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?

+3  A: 

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
+1  A: 

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
+42  A: 

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
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
This is truly awesome.
Aaron Maenpaa
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
Great thanks for sharing!
Masi
+2  A: 

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
:%!myreverse does not work for me in Vim. It gives the output: /bin/bash: myreverse: command not found
Masi
A: 

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
A: 

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
I guess that this could be done shorter. I did not get the long method to work.
Masi
A: 

I think what you really want is explained here.

André