Visual Studio has a nice feature that lets you format an XML (or other) document to make it more readable (Edit > Advanced > Format Document). I really like this feature and felt the need to add it (for XML at least) to my text editor of choice, Vim.
Vim lets you define your own functions as follows (note that user functions must start with a capital letter):
function! YourFunction()
" definition of function goes here
endfunction
Which is great, but it does involve learning Vim's scripting language - an activity which is not that high on my list right now. What I discovered is that the default build of Vim includes a Python interpreter which can be invoked on Vim's command line like this:
:py[thon] # python command goes here
With multi-line sessions being initiated with a termination sequence of your choosing:
:py[thon] << ENDPY
Where ENDPY
is an example of a termination sequence - it's just a symbol that you enter to tell Vim that you're finished writing your Python script/command so that it can go ahead and execute it - you could use any symbol you like; many examples use EOF
.
This multi-line bit is what you need to implement your Vim functions in Python - you create a Vim function wrapper around a block of Python; access to Vim's buffers etc. is provided in the form of a built-in Python module called
vim
(see
here for more info).
Continuing the dummy function definition above:
function! YourFunction()
python << ENDPY
import vim
# definition of function goes here (in Python!)
ENDPY
endfunction
You'd make this declaration in your .vimrc
file; to invoke it you'd issue the following to Vim while in normal mode:
:call YourFunction()
That's a bit more typing than you'd expect in Vim; to cut this down you'd map this function call to a command as follows (note that, as for functions, user commands must start with a capital letter):
command! -nargs=0 Yfunc call YourFunction()
So now you need only type the following to call your function:
:Yfunc
This is all well and good, but very abstract; plus it doesn't show you the vim
object in action. What prompted all of this in the first place was the need to format XML, so here is my solution, complete with command mapping:
function! PrettyXml()
python << ENDPY
import vim
from xml.dom import minidom
try:
b = vim.current.buffer
x = minidom.parseString( '\n'.join( b ) )
b[:] = None
for l in x.toprettyxml().split('\n'):
b.append( str( l ) )
del b[0] # remove empty first line
except Exception as ex:
print ex
ENDPY
endfunction
command! -nargs=0 Pxml call PrettyXml()
This shows me getting access to the contents of the current buffer - the list-like object vim.current.buffer
containing the lines of the buffer; using the Python Standard Library to achieve my goal and finally; updating the contents of the buffer.
This solution is a quick hack and as such has (at least) the following limitations:
- It only deals with the whole buffer; selections are supported by the
vim
object, but I haven't made use of them
- It only deals with whole XML documents; I haven't tried to support fragments
- It is a bit picky about XML declarations - if you specify
UTF-16
but encode with UTF-8
or ASCII, it will barf (just 'cos the Python minidom does) - arguably though, that's a feature.
This is not a very complicated example (and arguably quite a lazy solution) but what it does show is the potential - you can use the whole of the Python Standard Library to manipulate the contents of your buffer - there's nothing to stop you writing a function to tweet the current selection, for instance.