LoginSignup
1
1

More than 5 years have passed since last update.

icomplete-modeで入力を完了するためのコマンドをまとめる

Posted at

Emacsのバージョンを24.4に上げたところ、愛用していた iswitchb がobsoleteと言われました。移行先として icomplete を採用。helmido は、インターフェイスの大幅な変化にどうしても慣れませんでした。

icompele-mode を使っていると、補完、入力を完了して、制御を返すためのコマンドが複数選べます。

  • exit-minibuffer
  • minibuffer-complete-and-exit
  • minibuffer-force-complete-and-exit

の三つがそうです。
この三つの動作を、空気を読んで使い分けてくれるコマンドが欲しかったので書いてみました。

コード

.emacs
(icomplete-mode 1)

;; ミニバッファで補完を行いたくないコマンドのリスト
(defvar icomplete-exceptional-command-list
  '(dired-create-directory
    dired-do-copy
    dired-do-rename))

;; 起動時のカーソル位置を保持するための変数
(defvar icomplete-initial-point-max nil)
;; 起動時の補完候補リストを保持するための変数
(defvar icomplete-initial-completions nil)
;; 起動時に呼び出し元のコマンド名を保持するための変数
(defvar icomplete-this-command nil)

;; 起動時に上記の変数に値を代入するフックをかける
(add-hook 'icomplete-minibuffer-setup-hook
          (lambda ()
            (setq icomplete-initial-point-max (point-max))
            (setq icomplete-initial-completions
                  (completion-all-sorted-completions
                   (icomplete--field-beg) (icomplete--field-end)))
            (setq icomplete-this-command this-command)))

;; 入力完了のコマンド定義
(defun minibuffer-force-complete-and-exit-dwim ()
  "Complete the minibuffer with first of the matches and exit."
  (interactive)
  (cond ((member icomplete-this-command icomplete-exceptional-command-list)
         (exit-minibuffer))
        ((and (eq (point-max) icomplete-initial-point-max)
              (equal (car (completion-all-sorted-completions
                           (icomplete--field-beg) (icomplete--field-end)))
                     (car icomplete-initial-completions))
              minibuffer-default)
         ;; Use the provided default if there's one (bug#17545).
         (minibuffer-complete-and-exit))
        (t (minibuffer-force-complete)
           (completion--complete-and-exit
            (minibuffer-prompt-end) (point-max) #'exit-minibuffer
            ;; If the previous completion completed to an element which fails
            ;; test-completion, then we shouldn't exit, but that should be rare.
            (lambda () (minibuffer-message "Incomplete"))))))

;; 入力完了をリターンキーにバインド
(define-key icomplete-minibuffer-map [return]
  'minibuffer-force-complete-and-exit-dwim)

説明

icomplete-mode では、minibuffer-force-complete-and-exit ( C-j )を使うことで、補完候補の先頭を選んで補完し、入力を完了することが出来ます。また、デフォルト値が設定されていて、かつ、ユーザーからの入力がなかった場合は、デフォルト値が選択されます。

しかしながらこの minibuffer-force-complete-and-exit 、時々空気を読んでくれません。例えば、Rubyスクリプトの編集中、ruby-load-file ( C-c C-l )で実行を試みた時、デフォルト値には編集中のファイル名が設定されていて、かつ、入力はしていなかったにも関わらず、デフォルト値ではなく、補完候補の先頭(大抵の場合"./")が採用されてしまいます。他にも、 dired-mode でディレクトリの作成( + )を試みると、「補完できない」と言われて入力が完了できません。

もちろん、そういった時は、 exit-minibuffer ( C-m )を使うことで、所望の動作が得られます。でも、できたら、自分が使うコマンドは一つだけで、後は良きに計らって欲しい。ということで対症療法的に書いた代物が上記のコードです。

変更点は二つです。
第一に、 ruby-load-file のように、ミニバッファにプロンプト以外の文字列が最初から入っているタイプのコマンドでも、正しくデフォルト値が採用されるようになりました。第二に、 dired-create-directory のように、exit-minibuffer で入力を完了したいコマンドは、icomplete-exceptional-command-list に登録しておくことで、exit-minibuffer が呼ばれるようになりました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1