This is a great little python script that finds out what indentation is used in your source files. The author also provides a vim plugin, which is a life saver for anyone working with others on software projects. It prevents the complete mess that is the result of team members using their own indentation settings on source code. It analyses the text file, and provides reliable hints what indentation settings (tabs vs spaces, number of spaces etc) were used by the author. There is another plugin for the same purpose, which is basically the vimscript port of IndentFinder, but this latter is extremely slow, especially on large files (it seems vimscript was not really meant for parsing thousands of lines every time you open a file).
What I did not really like about IndentFinder was the way it invokes the python interpreter (thus increasing startup time and leaving room for errors), even if python bindings are supported in vim. One solution could have been simply to create a vim plugin from the python source, but then this would have meant increased maintenance efforts (copying changes from the python source to the vim plugin). Another possibility was to generate the vim plugin via setup.py from the python source.
First I added a new method to the main class in indent_finder.py:
--- a/indent_finder.py
+++ b/indent_finder.py
@@ -125,16 +125,21 @@ class IndentFinder:
self.clear()^M
f = open( fname )^M
l = f.readline()^M
while( l ):^M
self.analyse_line( l )^M
l = f.readline()^M
f.close()^M
^M
+ def parse_buffer( self, buf ):^M
+ self.clear()^M
+ for l in buf:^M
+ self.analyse_line(l)^M
+^M
def clear( self ):^M
self.lines = {}^M
for i in range(2,9): self.lines['space%d' % i] = 0^M
for i in range(2,9): self.lines['mixed%d' % i] = 0^M
self.lines['tab'] = 0^M
^M
self.nb_processed_lines = 0^M
self.nb_indent_hint = 0^M
It just makes it possible to call the parser with a buffer instead of a file name: vim opens the file and reads its contents into memory, thus it’s easier to pass the buffer itself to IndentFinder.
The second part is modifying setup.py to build the plugin from a fixed header, the python source and a fixed trailer. It turned out distutils is flexible enough to do this easily: you can subset the build class and do your special stuff in it. Easy:
#!/usr/bin/env python
from distutils.core import setup
from distutils.command.build import build
import os
import indent_finder
HEADER = """if exists('indent_finder') || !has('python')
finish
endif
let indent_finder=1
python << EOS
"""
TRAILER = """EOS
augroup indent
au!
au BufRead *.* :py import vim
au BufRead *.* :py fi = IndentFinder()
au BufRead *.* :py fi.parse_buffer(vim.current.buffer)
au BufRead *.* :py vim.command(fi.vim_output())
augroup END
"""
These are our fixed header and trailer parts. We just make sure python is supported in vim, and make IndentFinder parse the opened buffer. The result from IndentFinder is an actual vim command that adjusts indentation settings.
class build_vimscript(build):
vimscript = "indent_finder.vim"
pyscript = "indent_finder.py"
def run(self):
build.run(self) # call superclass first
if self.is_vimscript_outdated():
self.update_vimscript()
def is_vimscript_outdated(self):
pyst = os.stat(self.pyscript)
try:
vimst = os.stat(self.vimscript)
except OSError:
return True
else:
if pyst.st_mtime > vimst.st_mtime:
return True
return False
def update_vimscript(self):
pyf = open(self.pyscript, "r")
vimf = open(self.vimscript, "w")
vimf.write(HEADER)
for line in pyf:
vimf.write(line)
vimf.write(TRAILER)
vimf.close()
pyf.close()
Here we check that the vim plugin is older than the python source of IndentFinder. If it is, then the plugin is rebuilt. Calling the superclass in our run() method makes sure the other part of the build process is handled the usual way.
setup( name = "Indentation Finder",
version = indent_finder.VERSION,
description = "Finds of check the indentation used in programming source files",
author = "Philippe Fremy",
author_email = "phil at freehackers dot org",
maintainer = "Philippe Fremy",
maintainer_email = "phil at freehackers dot org",
license = "BSD license",
url="http://www.freehackers.org/Indent_Finder",
py_modules = [ "indent_finder" ],
cmdclass={"build": build_vimscript},
)
Here we’ve just added a new parameter to setup cmdclass tells distutils to use our class for building the package.
And that’s it. The .vim plugin is built and can be copied to
~/.vim/plugin/.