パイプラインで Emacs に出力を流し込む

軽く文句をつけつつも、wgrep はなかなか良さげ、ということで行番号付きでリンクしたり、実体参照変換 + 行番号付加 な私家版を作ってたりする。
で、Emacs 使いならやっぱり Emacs で結果を閲覧できればいいんじゃね、ということで Emacs にパイプできないかとか考えてみた。(以前 も似たようなことをやっているけど)
スクリプト側がサーバになって、Emacs は compilation-start でクライアントプログラムを走らせて結果を読むという方法。こんな感じで使う。

% grep -nr foo . | epipe
% ack --nogroup --nocolor --elisp compilation-start | epipe

で、Emacsgrep の結果が出力されるという寸法。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)