TextMate, Emacs and META indent-region
I haven't used GNU Emacs very much since switching to TextMate in 2005. One Emacs feature which I really miss in TextMate is indent-region. It lets you take an entire region of code, whatever its language, whatever its mix of tabs and spaces and indentation widths, and re-format it using your preferred indentation style.
But wait! Emacs has a batch mode, and you can drive it from TextMate. Many thanks to Gragusa's Things for showing the way.
The post on Gragusa's Things is specific to R code, but I'm more interested in re-formatting C and C++ code. Here's my first cut at a general TextMate Bundle to re-format code regardless of the source language:
#!/usr/local/bin/python2.6 """ Use Emacs to re-indent regions of the current buffer. Inspired by http://gragusa.wordpress.com/2007/11/11/textmate-emacs-like-indentation-for-r-files/ """ import tempfile import os import sys import subprocess # Use the same filename extension so Emacs will know which # mode to use. ext = os.path.splitext(os.environ["TM_FILEPATH"])[-1] outf = tempfile.NamedTemporaryFile(suffix=ext, delete=False) pathname = outf.name outf.write(os.environ["TM_SELECTED_TEXT"]) outf.close() args = [ "emacs", "-batch", pathname, # Assume no emacs-startup.el "--eval", "(setq indent-tabs-mode nil)", "--eval", '(c-set-style "java")', "--eval", "(setq c-basic-offset 4)", "--eval", "(indent-region (point-min) (point-max) nil)", "-f", "save-buffer"] p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() if p.returncode: print(err) inf = open(pathname, "r") sys.stdout.write(inf.read()) inf.close() os.remove(pathname)
NB:
- Due to the use of the
delete=False
keyword argument totempfile.NamedTemporaryFile
, this command bundle requires Python 2.6+. - TextMate on OS X 10.5 won't, by default, have
/usr/local/bin
in its path; hence the pathetic shebang.
Anyway, install this as a new TextMate command bundle, assign a Key Equivalent such as ⌘-Shift-R, and enjoy.