« ^ »

Emacsの外部参照機能xref.elについて考える

所要時間: 約 3分

Emacsのクロスリファレンス用ライブラリであるxref.elについて調べたり考えたりする。

xref.elとは

xref.elはタグジャンプなどの機能のためのI/Fを提供している。一般的に関数の名前の上にカーソルを当てて M-. を実行するとカーソルの定義位置にジャンプする。この時 xref-find-definitions が呼び出されているが、この関数はxref.elに定義されている。

https://elpa.gnu.org/packages/xref.html

xrefバックエンドを実装する

xrefを使用してタグジャンプなどを実現するには、xrefバックエンドが実装されている必要がある。通常、各種言語のxrefバックエンドは既に実装されている事が多いだろう。しかし新しい言語や、ユーザーが少ない言語、自作言語の場合は、xrefバックエンドを実装する必要に迫られる事もある。ここでは、簡単なxrefバックエンドを実装する事で、その実装方法を確認する。

ここでは、全ての機能を実装しない。 xref-find-definitions によって特定の位置にジャンプする機能を実装し xref-go-back によってジャンプ先からジャンプ元に戻れる事までを確認する。便宜上 symdon というxrefバックエンドを実装する事にする。

xrefバックエンドは xref-backend-functions に登録される。テストで実装するバックエンド以外を無効化するために、変数をnilに設定しておく。

(setq-local xref-backend-functions nil)

xrefバックエンドのシンボルを返す関数を実装する。ここでは symdon というシンボルにしている。このシンボルによって各種バックエンドは処理を分岐する。この関数は先程初期化した xref-backend-functions に登録する事で有効になる。

(defun symdon--xref-backend () 'symdon)

(add-to-list 'xref-backend-functions #'symdon--xref-backend)

xref-backend-identifier-completion-tablexref-find-definitions を実行した際に使用される、識別子の補完テーブルを返す関数を返す関数を実装する。識別子の補完テーブルは文字列のリストになる。補完テーブルからデータを読み出し、それらのリストになるようにデータを変換し返す。

(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql 'symdon)))
  (lambda (string pred action)
    '("aaa" "bbb" "ccc")))

xref-backend-definitionsxref-backend-identifier-completion-table によって選択されたシンボルの位置を特定し、外部参照として返す。外部参照は xref-make を用いて作成する。先頭のスロットは summary 、その次のスロットは location だ。 summary には文字列を、 location には位置を設定する。位置の形式はいくつかある。ここではバッファの位置を表現する形式である xref-buffer-location を返している。またここでは、スクラッチバッファの先頭から200ポイントの位置を指定している。通常の実装では、きちんと位置を特定する必要がある。

(cl-defmethod xref-backend-definitions ((_backend (eql 'symdon)) symbol)
  `(,(xref-make "testing"
       (make-xref-buffer-location :buffer (get-buffer "*scratch*") :position 200))))

ここまで実装すると、 xref-find-definitionsxref-go-back は動作するようになる。

xref系で用意されているコマンド

xref.el.gzには以下の関数がコマンドとして用意されている。

  • xref-find-apropos
  • xref-find-backend
  • xref-find-definitions
  • xref-find-definitions-at-mouse
  • xref-find-definitions-other-frame
  • xref-find-definitions-other-window
  • xref-find-references
  • xref-marker-stack-empty-p
  • xref-matches-in-directory
  • xref-matches-in-files
  • xref-pop-marker-stack
  • xref-references-in-directory

(autoloadが宣言されている関数)

その他

Emacs 26.1の段階ではxref.el.gzには実験段階である旨の記述がある。

;; NOTE: The xref API is still experimental and can change in major,
;; backward-incompatible ways.  Everyone is encouraged to try it, and
;; report to us any problems or use cases we hadn't anticipated, by
;; sending an email to emacs-devel, or `M-x report-emacs-bug'.

翻訳すると以下の意味だ。

注:外部参照APIはまだ実験段階であり、大幅に変更される可能性があります。
後方互換性のない方法。誰もがそれを試すことをお勧めします、そして
予期していなかった問題やユースケースを報告してください。
emacs-devel、または `M-xreport-emacs-bug 'にメールを送信します。

Emacs 28にはその記述はなくなっていた。