TextMate, Emacs and META indent-region
[cross-posted from the Desert Moon blog.]
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.