Hi-lockでバッファ内のキーワードをいい感じに強調する

あったらいいなとは思ってたけど標準機能にあったことは今日まで知らなかったシリーズ


![スクリーンショット 2024-12-08 7.38.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/cac686d8-2200-c508-fdd2-28894df31a18.png)

## 何がしたいのか

バッファ内にある特定の文字列を色付けて強調表示したい。

ユースケースとしてはいくつか考えられるけれど、コードリーディング中に注目したい変数やメソッドなどに色をつけていくなどはわかりやすいかもしれない。

## どうすればいいのか

### 一時的に表示 `M-x highlight-xxxxx`コマンド

以下のGIFアニメは`M-x highlight-symbol-at-point`や`M-x highlight-regexp`を使ってみたところ。

![aa182207b5ff911ed9c4850ddbd60ce7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/98b1a66e-a958-758a-d272-9e7629f132ab.gif)

たぶんいちばん使いやすいのは`M-x highlight-symbol-at-point`です。

![スクリーンショット 2024-12-12 21.39.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/c93146a0-f470-722a-7e51-7d58be544d5f.png)

 * `M-x highlight-symbol-at-point`
   * カーソル位置の関数名や変数名のようなシンボルを強調表示します
     * 内部的には `"\\_<...\\_>` で括られたパターンになります
     * たとえば`red`を強調して`redirection`のような部分文字列に誤爆しません
   * 色は適当に割り当てられます
 * `M-x highlight-regexp`
   * 正規表現で入力します (Emacs特有の癖があるやつ)
     * リージョン選択していたらデフォルト選択されます
   * 色は選べますが、まだ使ってない色がいい感じにサジェストされてます
 * `M-x highlight-phrase`
   * 小文字で指定すると、大文字小文字を区別し
     * 名前でわかりにくいですが正規表現でも書けます
   * `highlight-symbol-at-point`のように暗黙的なシンボル境界は不可されません
     * `highlight`を指定すると、`Highlights`(の`s`以外)や`highlighting`(の`ing`以外)に色がつきます
     * 正規表現で明示的に指定すれば単語全体に色をつけることもできます
   * 色は選べますが、まだ使ってない色がいい感じにサジェストされてます

### `M-x highlight-phrase`をちょっと使いやすくする

`M-x highlight-phrase`もいいのですが、カーソル位置のキーワードをいい感じに拾ってきてくれません。なので、自分でラッパーを用意することもできます。

```elisp
(defun my-highlight-phrase (regexp &optional face)
  "Set face of each match of phrase REGEXP to FACE."
  (interactive
   (list
    (hi-lock-regexp-okay
     (read-regexp "Phrase to highlight"
                  (rx-to-string
                   (list : (if (region-active-p)
                               (buffer-substring-no-properties (region-beginning) (region-end))
                             (thing-at-point 'symbol)))
                   t)
                  'regexp-history-last))
    (hi-lock-read-face-name)))
  (highlight-phrase regexp face))
```

## `M-x hi-lock-mode`

ここまでの強調表示機能は、`hi-lock-mode`というマイナーモードが提供しています。上記のコマンド起動時にマイナーモードが有効化されていなければ、暗黙的に有効化されます。

`hi-lock-mode`を有効化するとき、ファイル内に以下のような記述があると`Add patterns from this buffer to hi-lock? (y or n)`と尋ねられて有効化されます

```elisp
;; Hi-lock: (("search"  (0 'hi-salmon prepend)))
;; Hi-lock: (("\\_<defcustom\\_>" (0 'hi-blue prepend)))
;; Hi-lock: (("\\_<const\\_>" (0 'hi-green prepend)))
;; Hi-lock: (("\\_<string\\_>" (0 'hi-pink prepend)))
;; Hi-lock: (("Search" (0 'hi-yellow prepend)))
```

## 強調箇所の永続化

`M-x hi-lock-write-interactive-patterns`を実行すると、バッファ内で強調している強調キーワードをカーソル位置にコメントアウトされた状態で展開します。

ただし、下記のようにやたら冗長な行が出力されるので気をつけてください。

```elisp
Hi-lock: ((#[257 "\301\300\305\302\242\306#*\207" ["[ 	]+" t ("without") search-spaces-regexp case-fold-search re-search-forward t] 5 ("/Applications/Emacs.app/Contents/Resources/lisp/hi-lock.elc" . 28983)] (0 'hi-yellow prepend)))
```

先述のようにいい感じに削っても動作しますが、`highlight-phrase`のようにcase-sensitiveな(大文字小文字を問わない)強調はできなくなるので気をつけてください。

## 機能の呼び出し方

`hi-lock-mode`を有効化すると、メニューバーの`Edit`の中にもメニューが生えてきます。

![スクリーンショット 2024-12-13 1.18.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/576e3634-83f0-7fed-4d8b-a8d2bbd3789b.png)

メニューバー自体が無視されがちな不憫なやつですが…

## 参考記事

 * [(Emacs) Hi-lock modeを使う - Weblog on mebius.tokaichiba.jp](https://ynomura.pgw.jp/archives/2011/01/emacs_hilock_mo.html)
 * [Highlight Interactively (GNU Emacs Manual (Japanese Translation))](https://ayatakesi.github.io/emacs/29.4/html/Highlight-Interactively.html)