anything-grep.elを使うと、シェルコマンドとしてgrepなどの検索をかけて、その結果をanythingで絞り込むことができる。ディレクトリ以下のファイルすべてを一発で検索、などできるのが魅力。
EmacsWiki: anything-grep.el 現在の最新版は1.27。
例えば、anything-regexpの場合
これは、カレントバッファに対して正規表現で絞り込みをかけることができる。Regexpに、
[[:digit:]]\{4,\}
とか指定すると、マッチした行が、マッチしている部分がカラーリングされて候補に出てくる。
anything-grepだと
ターミナルで
ack --nogroup '\d{4}'
anything-grepのコマンドで同じように検索かけた場合、結果は候補としてでてくるけど、マッチしている部分のカラーリングはされていない。
ackコマンドでなく
grep -nH -e '[[:digit:]]{4\}' *.el
とやっても同じ結果だった。
原因
追いかけてみたところ、マッチした部分のカラーリングはagrep-fontify
関数で行っているようだ。ここで検索コマンドから返ってきた結果を加工している。
(while (re-search-forward "\\(\033\\[01;31m\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)" nil t) (put-text-property (match-beginning 2) (match-end 2) 'face grep-match-face) (replace-match "" t t nil 1) (replace-match "" t t nil 3))
この部分で、マッチしてきた部分のfaceをgrep-match-face
にセットし、それ以降エスケープシーケンスを除去している。つまり、この正規表現にマッチするようにコマンドから出力されていないといけない、ということ。
grepを使った場合は、agrep-do-grep
関数内で
(when (eq grep-highlight-matches t) ;; Modify `process-environment' locally bound in `call-process-shell-command'. (setenv "GREP_OPTIONS" (concat (getenv "GREP_OPTIONS") " --color=always")) ;; for GNU grep 2.5.1 (setenv "GREP_COLOR" "01;31") ;; for GNU grep 2.5.1-cvs (setenv "GREP_COLORS" "mt=01;31:fn=:ln=:bn=:se=:ml=:cx=:ne"))
という定義があった。grep-highlight-matches
がt
であれば勝手に環境変数でオプションを調整してエスケープシーケンスを出すようにしてくれるようだ。
(custom-set-variables '(grep-highlight-matches t))
とやったら、grepコマンドを使った検索で結果のマッチ部分がカラーリングされるようになった。
しかしackでは
ackの場合、検索結果のマッチ部分は\e[01;31m
のエスケープシーケンスではカラーリングされない。デフォルトではblack on_yellow
、つまり\e[30;43m
となっている。これはオプションもしくは環境変数で変えることができるが、指定出来るのはTerm::ANSIColor
のATTRIBUTESに登録されているものに限られるようだ。
sub print_match_or_context { ... s/$regex/Term::ANSIColor::colored( substr($_, $-[0], $+[0] - $-[0]), $ENV{ACK_COLOR_MATCH} )/eg ) { ... }
で、この$ENV{ACK_COLOR_MATCH}
は"bold red"を指定することでgrepと同じカラーリングにできるのだけど…
$ ack -h --color --color-match='bold red' --nogroup '\d{4}' | hexdump -C | head 00000000 3b 3b 20 43 6f 70 79 72 69 67 68 74 20 28 43 29 |;; Copyright (C)| 00000010 20 1b 5b 31 3b 33 31 6d 32 30 30 37 1b 5b 30 6d | .[1;31m2007.[0m| 00000020 20 7e 20 1b 5b 31 3b 33 31 6d 32 30 31 31 1b 5b | ~ .[1;31m2011.[| 00000030 30 6d 2c 20 54 61 73 73 69 6c 6f 20 48 6f 72 6e |0m, Tassilo Horn| 00000040 2c 20 61 6c 6c 20 72 69 67 68 74 73 20 72 65 73 |, all rights res| 00000050 65 72 76 65 64 2e 1b 5b 30 6d 1b 5b 4b 0a 3b 3b |erved..[0m.[K.;;| 00000060 20 43 6f 70 79 72 69 67 68 74 20 28 43 29 20 1b | Copyright (C) .| 00000070 5b 31 3b 33 31 6d 32 30 30 39 1b 5b 30 6d 2c 20 |[1;31m2009.[0m, | 00000080 41 6e 64 79 20 53 74 65 77 61 72 74 2c 20 61 6c |Andy Stewart, al| 00000090 6c 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 |l rights reserve|
残念なことに出力されるエスケープシーケンスは\e[1;31m
となっていて、agrep-fontifyで使われている正規表現にはマッチしない。
ためしにagrep-fontifyの部分の定義を
317c317 < (while (re-search-forward "\\(\033\\[01;31m\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)" nil t) --- > (while (re-search-forward "\\(\033\\[1;31m\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)" nil t)
と変更してやって、
ack --nogroup --color-match='bold red' '\d{4}'
という検索コマンドを指定したところ、マッチ部分がカラーリングされるようになった。
解決策
ackでの検索結果のマッチカラーリングを実現させるには。
ack側では、App::Ack
がTerm::ANSIColor
を使ってカラーリングの指定をしていて、その中では
'bold' => 1,
と数値の1で指定されてしまっているので、\e[01;31m
を出力させるようにするのは難しい。
anything-grep.elのagrep-fontify
に処理が行く前にdefadviceを使ってコマンド実行結果を先に加工するのが良いだろうか。
この正規表現部分をカスタム変数にして自由に設定出来るようにid:rubikitchさんにお願いしてみましょうか。
他になにか良い方法あるかなぁ…