簡単な「関数の完了」関数をどのように記述すればよいですか?


9

私はマジックを編集するための主要なモード、ザ・ギャザリングのデッキを書くことを検討しています。

そのほとんどは簡単なようですが、1つ質問があります。約15,000枚のユニークなマジックカード(ユニークな名前のカード)が利用可能です。ポイント完了関数を書くことで、それらに対して完了できるようにしたいと思います。私は、モードのベースとなる一連の単語に対して完了するだけで、これまで何も見つからなかったcapf関数の簡単で基本的な例を探していました。これを始めるための良い例を知っていますか?そして、あなたはそれが良いパフォーマンスを得るのは簡単だと思いますか、または私は自分のデータ構造を書かなければなりませんか(おそらく私はトライのように考えています)。

明らかに、新しいカードなどと同期する方法を見つける必要があります。将来的には、カード名だけでなく他の特性でカードを検索できるようになるかもしれませんが、それでも待つことができます。

回答:


17

ドキュメンテーション

関数のポイントでのAPIの完了は、 completion-at-point-functions

このフックの各関数は引数なしで順番に呼び出され、その時点で適用できないことを意味するnilを返すか、補完を実行するための引数のない関数(推奨)、またはフォームのリスト(START END COLLECTION 。PROPS)STARTおよびENDはエンティティを区切るためのポイントであり、ポイントを含める必要があります。COLLECTIONはエンティティを完了するために使用する完了テーブルで、PROPSは追加情報のプロパティリストです。

startendそしてprops明白ですが、の形式がcollection適切に定義されていないと思います。そのためには、try-completionまたはのドキュメントを見ることができますall-completions

COLLECTIONがalistの場合、キー(要素の車)は可能な補完です。要素がコンスセルでない場合、要素自体が補完候補になります。COLLECTIONがハッシュテーブルである場合、文字列またはシンボルであるすべてのキーが補完候補になります。COLLECTIONがオブジェクト配列の場合、オブジェクト配列内のすべてのシンボルの名前が補完候補になります。

COLLECTIONは、補完自体を実行する関数にすることもできます。これは、値STRING、PREDICATE、nilの3つの引数を受け取ります。それが返すものはすべて「try-completion」の値になります。

以下は/etc/dictionaries-common/words、バッファ内の単語を完成させるためにで定義された単語を使用するポイントでの補完の簡単な例です

(defvar words (split-string (with-temp-buffer
                              (insert-file-contents-literally "/etc/dictionaries-common/words")
                              (buffer-string))
                            "\n"))

(defun words-completion-at-point ()
  (let ((bounds (bounds-of-thing-at-point 'word)))
    (when bounds
      (list (car bounds)
            (cdr bounds)
            words
            :exclusive 'no
            :company-docsig #'identity
            :company-doc-buffer (lambda (cand)
                                  (company-doc-buffer (format "'%s' is defined in '/etc/dictionaries-common/words'" cand)))
            :company-location (lambda (cand)
                                (with-current-buffer (find-file-noselect "/etc/dictionaries-common/words")
                                  (goto-char (point-min))
                                  (cons (current-buffer) (search-forward cand nil t))))))))

補完関数は、ある時点で単語を検索し(ライブラリthingatptは単語の境界を見つけるために使用されます)、/etc/dictionaries-common/wordsファイル内の単語に対してそれを補完します。このプロパティ:exclusiveno、失敗した場合にemacsが他のcapf関数を使用できるように設定されます。最後に、会社モードの統合を強化するためにいくつかの追加プロパティが設定されています。

パフォーマンス

私のシステムの単語ファイルには99171エントリがあり、emacsは問題なくそれらを完了することができたので、15000エントリは問題にならないと思います。

会社モードとの統合

会社モードcompletion-at-point-functionscompany-capfバックエンドの使用と非常によく統合されているため、そのまま使用できますがprops、capf関数の結果に追加で返すことで、会社が提供する補完を強化できます。現在サポートされている小道具は

:company-doc-buffer -現在の候補者のメタデータを表示するために会社が使用

:company-docsig -ミニバッファーで候補者に関するメタデータをエコーするために会社が使用

:company-location -現在の候補者の場所にジャンプするために会社によって使用されます


あら!完全な回答をありがとう!私はこれを少し試してみて、その後受け入れます。会社のヒント(実際に使用しています)に感謝します。
Mattias Bengtsson、2015

おかげで、本当に役立ちました。カスタム補完を簡単に構成できるようになりました:)
clemera

よかった:)
Iqbal Ansari

0

@Iqbal Ansariは素晴らしい答えを出しました。ここに補足的な答えがあります、それが役に立てば幸いです。

2009年のemacsクラシック補完メカニズムを使用した実装を次に示します。

;; this is your lang's keywords
(setq xyz-kwdList
      '("touch"
       "touch_start"
       "touch_end"
       "for"
       "foreach"
       "forall"
       ))

以下は、補完を行うコードです。

(defun xyz-complete-symbol ()
  "Perform keyword completion on word before cursor."
  (interactive)
  (let ((posEnd (point))
        (meat (thing-at-point 'symbol))
        maxMatchResult)

    ;; when nil, set it to empty string, so user can see all lang's keywords.
    ;; if not done, try-completion on nil result lisp error.
    (when (not meat) (setq meat ""))
    (setq maxMatchResult (try-completion meat xyz-kwdList))

    (cond ((eq maxMatchResult t))
          ((null maxMatchResult)
           (message "Can't find completion for “%s”" meat)
           (ding))
          ((not (string= meat maxMatchResult))
           (delete-region (- posEnd (length meat)) posEnd)
           (insert maxMatchResult))
          (t (message "Making completion list…")
             (with-output-to-temp-buffer "*Completions*"
               (display-completion-list 
                (all-completions meat xyz-kwdList)
                meat))
             (message "Making completion list…%s" "done")))))

以下は、ido-modeのインターフェースを使用した実装です。はるかに簡単です。

(defun abc-complete-symbol ()
  "Perform keyword completion on current symbol.
This uses `ido-mode' user interface for completion."
  (interactive)
  (let* (
         (bds (bounds-of-thing-at-point 'symbol))
         (p1 (car bds))
         (p2 (cdr bds))
         (current-sym
          (if  (or (null p1) (null p2) (equal p1 p2))
              ""
            (buffer-substring-no-properties p1 p2)))
         result-sym)
    (when (not current-sym) (setq current-sym ""))
    (setq result-sym
          (ido-completing-read "" xyz-kwdList nil nil current-sym ))
    (delete-region p1 p2)
    (insert result-sym)))

単語のリストとしてxyz-kwdListを定義する必要があります。


2
-1、悪化した方法で完了インターフェイスを再発明するために行くためのnullオーバーnotとキャメル記法識別子とだけ自分自身のモードで意味をなすギリシャのシンボルを使用して。
wasamasa

3
-1についての質問に答えなかった場合completion-at-point-functionsnullvs について@wasamasaに同意しませnotん)。
npostavs 2015

3
@XahLeeの関数は、completion-at-point-functions完了データを返すことになっていますが、それ自体では完了を実行しません。したがって、回答の関数はのエントリとして使用できませんcompletion-at-point-functions
npostavs 2015

1
@npostavsああ、なるほど。あなたが正しいです。ありがとう!
Xah Lee

4
@npostavsこの種の関数は引き続き機能しますが、実際にこの方法で補完関数を作成することは、ドキュメント化されたインターフェイスに反するため、お勧めしません。
ドミトリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.