軽く文句をつけつつも、wgrep はなかなか良さげ、ということで行番号付きでリンクしたり、実体参照変換 + 行番号付加 な私家版を作ってたりする。
で、Emacs 使いならやっぱり Emacs で結果を閲覧できればいいんじゃね、ということで Emacs にパイプできないかとか考えてみた。(以前 も似たようなことをやっているけど)
スクリプト側がサーバになって、Emacs は compilation-start でクライアントプログラムを走らせて結果を読むという方法。こんな感じで使う。
% grep -nr foo . | epipe
% ack --nogroup --nocolor --elisp compilation-start | epipe
で、Emacs に grep の結果が出力されるという寸法。UNIX Domain Socket オンリーとか、grep-mode オンリーとか改良すべき点はいくつかあるような気がするけど、とりあえず。
真っ先に思いつくのは make-network-process で Emacs 側をサーバにしてスクリプトから流し込む方法なんだけど、スクリプト1個ですむということで、この方針で。
import sys import os import re import socket import fileinput import threading import subprocess SERVER_FILE = '/tmp/eless' EMACSCLIENT = 'emacsclient' def serve(s, args): (conn, address) = s.accept() for line in fileinput.input(args): conn.sendall(line) conn.close() def sexp_str(s): s = s.replace('\\', '\\\\') s = s.replace('"', '\\"') return '"%s"' % s def escape_shell_arg(s): return "'%s'" % s.replace("'", r"'\''") def main(args): if os.path.exists(SERVER_FILE): os.remove(SERVER_FILE) s = socket.socket(socket.AF_UNIX) s.bind(SERVER_FILE) s.listen(5) th = threading.Thread(target = serve, args = (s, args)) th.start() sexp = ("""(let ((default-directory %s))\n""" """ (compilation-start "%s %s --client %s" 'grep-mode)\n""" """ (when (getenv "WINDOW")\n""" """ (call-process "screen" nil nil nil "-X" "select" (getenv "WINDOW"))))""") sexp = sexp % (sexp_str(os.getcwd() + '/'), escape_shell_arg(sys.executable), escape_shell_arg(sys.argv[0]), escape_shell_arg(SERVER_FILE)) subprocess.call([EMACSCLIENT, '-e', sexp]) th.join() s.close() def socket_cat(): s = socket.socket(socket.AF_UNIX) try: s.connect(SERVER_FILE) fp = s.makefile() try: for line in fp: sys.stdout.write(line) finally: fp.close() finally: s.close() if __name__ == '__main__': import optparse parser = optparse.OptionParser() parser.add_option('--client', action = 'store_true', dest = 'client', default = False) (options, args) = parser.parse_args() if options.client: socket_cat() else: main(args)