Skip to content

Instantly share code, notes, and snippets.

@buzztaiki
Last active March 14, 2024 01:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buzztaiki/7d58fc70f322ba1ec53248e1ab1961e9 to your computer and use it in GitHub Desktop.
Save buzztaiki/7d58fc70f322ba1ec53248e1ab1961e9 to your computer and use it in GitHub Desktop.
Emacs の補完の仕組みメモ

Emacs の補完の仕組みメモ

大昔の事しか知らなかったから、最近の仕組みまわりをなんとなく調べてみたメモ。Emacs 28.1。

基本

補完を支える基本は昔と変わってなくて all-completionstry-completion。引数も Emacs 20 の昔と変わってない模様。

ミニバッファの補完

completing-read 等をしたときに M-TAB で発動する補完は minibuffer-complete

補完の為の値は minibuffer-completion-tableminibuffer-completion-predicate などのバッファローカル変数で持っている。

completion-styles

補完方法のリストを completion-styles でユーザーが定義できるようになっている。

completion-styles を意識した補完の関数は completion-all-completionscompletion-try-completion。また、ソートして結果を返すための completion-all-sorted-completions が準備されている。

これらの関数は completion-all-completionscompletion-styles を順に試して候補が見つかったらそれを返す。

これらの補完関数を使った場合、completion table が関数 (プログラム補完) ならば completion-metadata を使ってその候補におけるメタデータを取得できる。このメタデータを使ってソート順などを表現するようになっている。

completion-category-overrides を設定する事で、コンテキストに合わせた補完スタイルが選択できる。このキーはメタデータ category で指定される。

各スタイルは completion-styles-alist に定義されている。

completion-all-completions

(completion-all-completions string table pred point &optional metadata)

point はカーソルの位置。また、引数 metadata でメタデータを上書きできる。 返り値に注意で、リストが返ってくるんだけど、最後のコンセルの cdr が nil じゃない事がある。base-size と呼ばれていて、共通部分をハイライトするのに使われている。

つまり、普通の候補一覧が欲しいときは以下のようにする。

(let ((collection '("fuga_hoge" "hoge_fuga" "hoge"))
      (completion-styles '(partial-completion)))
  (let ((candidates (completion-all-completions "hoge" collection nil 4)))
    (when-let (last (last candidates)) (setcdr last nil))
    candidates))

プログラム補完

補完関数に渡す completion table はコレクションだけではなく関数も渡せる。この辺は昔と変わらない。 プログラム補完の関数を便利に作るための completion-table-dynamiccompletion-table-with-cache が準備されている。

プログラム補完するには (funcall table string predicate t) のように呼ぶ。 補完される側にとってはカスタマイズ性が高くてよいのだけど、補完する側にとっては自由にマッチさせられない事になるので、わりと困りものな気もする。

completion-metadata

プログラム補完の関数を (funcall table string predicate 'metadata) のように呼ぶ事でメタデータを取得できる。 メタデータの種類は以下の通り (completion-metadata の docstring から引用)

  • category: the kind of objects returned by all-completions. Used by completion-category-overrides.
  • annotation-function: function to add annotations in *Completions*. Takes one argument (STRING), which is a possible completion and returns a string to append to STRING.
  • affixation-function: function to prepend/append a prefix/suffix to entries. Takes one argument (COMPLETIONS) and should return a list of annotated completions. The elements of the list must be three-element lists: completion, its prefix and suffix. This function takes priority over annotation-function when both are provided, so only this function is used.
  • group-function: function for grouping the completion candidates. Takes two arguments: a completion candidate (COMPLETION) and a boolean flag (TRANSFORM). If TRANSFORM is nil, the function returns the group title of the group to which the candidate belongs. The returned title may be nil. Otherwise the function returns the transformed candidate. The transformation can remove a redundant prefix, which is displayed in the group title.
  • display-sort-function: function to sort entries in *Completions*. Takes one argument (COMPLETIONS) and should return a new list of completions. Can operate destructively.
  • cycle-sort-function: function to sort entries when cycling. Works like display-sort-function.

なんと group-function なんて物まで存在していた。進化している。

補完システムはこれらを使っていい感じに表示してくれる。

一部の属性は、存在しない場合 completion-extra-properties を使って代替できる。

デファクトになった company 向けのメタデータ

company では追加のメタデータを導入している。company が覇権を取っていた時期が長かったのもあって、これらの属性はほぼ業界標準になっている (ように見える)。 company 以外の補完システムでもこのテキストプロパティは使われていて、なんと elisp-mode が作る補完候補にも含まれている。

使われているのは

  • company-docsig
  • company-doc-buffer
  • company-location
  • company-kind
  • company-prefix-length

など。

*Completon* バッファ

WIP

通常バッファの補完

WIP

completion-at-point

WIP

completion-in-region

WIP

pcomplete

WIP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment