I would like to write a python script that parses some vim data and returns a result. For example, we'll turn numbers, separated by lines, into a sorted list of unique numbers. If we had this as the input:

enter image description here

The python script would do:

import sys
sys.stdout.write('\n'.join([str(i) for i in (sorted(set([int(k) for k in sys.argv[-1].split()])))]))

This would expect the text from vim to be passed as an arg, so perhaps something like:

:imap <c-t> <c-r>=system('x.py <text_from_vim>')<cr>

And now vim would look like:

enter image description here

How could this be done?

  • 1
    Filter? :%! ... – B Layer May 31 at 2:44
  • 1
    What it does is take a range of lines and sends them as stdin to a command and the result replaces those lines. So, for example, :%!sort will sort the entire file (if you have a sort command in your shell) since % is short hand for "the whole file". – B Layer May 31 at 2:50
  • 1
    That's right.. yep. (You don't need to enter the range if you hit : from Visual mode. It's prepopulated.) – B Layer May 31 at 2:56
  • 2
    Great opportunity to learn how to call external filters, but :%sort | %!uniq should do it, or :%!sort | uniq if you want to use external sort (I dont think vim has a builtin :uniq but I could be wrong). – D. Ben Knoble May 31 at 14:16
  • 1
    @D.BenKnoble A couple hours ago I happened to be reading :h list-modification which includes an example that caught my eye (for no reason in particular, really). Fast forward to now, I see your comment, and somewhere a little bell starts to ring. The example? :call uniq(sort(list)). Oh, coincidences. You add such spice to life. ;) – B Layer Jun 17 at 12:09

Thanks to @BLayer for the suggestion here. Here is a 5s video of the result.

In summary, what was done is:

  • The external (or internal) script will receive the lines as input to stdin. If sending the full file, you can use :%!, and if sending a visual selection, selecting the text and entering cmd mode will automatically do this, '<,'>.
  • In the python (or any other extern script) you'd read stdin as text. In python, this is currently done by using sys.stdin.read(). So the full interaction looks like:

In vim:


In python:

import sys
input_string = sys.stdin.read()
sys.stdout.write('\n'.join([str(i) for i in sorted(set([int(k) for k in input_string.split()]))]))

Additionally, you can pass command-line args by just entering them right into vim, for example:

:'<,'>!./x.py arg1 arg2
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.