5

comint-mode に基づいて、派生モードを作成しています。このモードはコマンドライン プログラム (GRASS gis) へのインターフェイスであり、comint モード補完はプログラムに対して機能します。を介して、プログラムへの引数を完了するためのサポートを追加しようとしていcompletion-at-point-functionsます。おもちゃの例は次のとおりです。

(setq my-commands 
      '(("ls"
         ("my-completion-1")
         ("my-completion-2"))
        ("mv"
         ("my-completion-3")
         ("my-completion-4"))))


(defun my-completion-at-point ()
  (interactive)
  (let ((pt (point)) ;; collect point
        start end)

    (save-excursion ;; collect the program name
      (comint-bol)
      (re-search-forward "\\(\\S +\\)\\s ?"))
    (if (and (>= pt (match-beginning 1))
             (<= pt (match-end 1)))
        () ;; if we're still entering the command, pass completion on to
      ;; comint-completion-at-point by returning nil

      (let ((command (match-string-no-properties 1)))
        (when (member* command my-commands :test 'string= :key 'car)
          ;; If the command is one of my-commands, use the associated completions 
          (goto-char pt)
          (re-search-backward "\\S *")
          (setq start (point))
          (re-search-forward "\\S *")
          (setq end (point))
          (list start end (cdr (assoc command my-commands)) :exclusive 'no))))))

(push 'my-completion-at-point completion-at-point-functions)

これはほとんど機能します。プログラム名の正常な補完が得られます。ただし、lsコマンドラインで入力した場合、タブを押すと挿入さmy-completion-れ、2 つのオプションが提供されません。タブをもう一度押すmy-completion-と、2 回目の挿入が行われるので、ls my-completion-mycompletion-.

私の実際のコードには、複数行のコマンドをチェックするための数行が含まれていますが、完了コードは変更されていません。このバージョンのコードでは、プログラム名の 1 つで始まる行でタブを押しますmy-commands。コマンドを完了するために使用できる引数のリストが表示されますが、バッファには何も挿入されず、リストは引数の最初の数文字を入力して絞り込まれないようにします。

マニュアルを読みましたが、関数の正しい書き方がわかりませんcompletion-at-point。私が見逃しているアイデアはありますか?

を簡単に見ましたpcompleteが、 は「ドキュメント」をよく理解しておらず、何の進展もありませんでした。

4

1 に答える 1

8

問題は、ポイントで引数の境界を見つけて返す方法にあるようstartですendstart詳細を確認するのに十分な時間をかけてデバッグしませんでしたが、関数を対話的に呼び出すと、 andに対して同じ値が返されることがわかると思います。endこれは、補完 UI が認識していないことを意味します。ポイントの引数を使用して、渡した補完テーブルから選択します。

関数の最後の部分を次のように変更することは、1 つの修正のようです。

(when (member* command my-commands :test 'string= :key 'car)
  ;; If the command is one of my-commands, use the associated completions 
  (goto-char pt)
  (let ((start
         (save-excursion
           (skip-syntax-backward "^ ")
           (point))))

    (list start pt (cdr (assoc command my-commands)) :exclusive 'no)))))))

の要素として追加すると、これにより期待される結果が得られcompletion-at-point-functionsます。

ここではskip-syntax-backward、正規表現検索の代わりに使用しました。これは、この種のことに対して少し慣用的な Elisp だと思います。構文クラス「空白」にないものを横切ってポイントを後方に移動するように言っているだけです。スキップ構文関数は、ポイントの値ではなく移動距離を返すためpoint、save-excursion の最後に への呼び出しを追加する必要があります。

このような関数で正規表現検索を使用する場合は、通常、t4 番目の引数 を渡すことをお勧めしnoerrorます。これにより、一致に失敗した場合にユーザーにエラーが渡されなくなります。ただし、これは、戻り値がnilであるかどうかを自分で確認する必要があることを意味します。

最後にpush、補完関数を追加する代わりにadd-hook、次のように使用することをお勧めします。

(add-hook 'completion-at-point-functions 'my-completion-at-point nil t)

これは 2 つの便利なことを行います。関数を追加する前に、関数が既にフック内にあるかどうかをチェックし、( t4 番目の引数を渡すことによって)ポイント完了フックのバッファー ローカルlocal値に関数を追加するだけです。TAB キーを押したときに他のすべての Emacs バッファーでこれらの補完を使用したくないため、これはほぼ確実に必要なことです。

于 2012-04-23T09:17:52.977 に答える