あどけない話

インターネットに関する技術的な話など

Emacs補完候補の選択を便利に

今話題のauto-complete.elを使ってみましたが、以下の点が使いづらく、使うのを止めてしまいました。

  • 候補が最大10個しか出ない
    • 10個以上の候補がある場合、次に打つべき文字が分らない
  • バッファの最下部でメニューが表示されると、勝手にスクロールされる

個人的には、Emacsが提供する標準の Completion List モードを拡張する方がいいなぁと思いました。Completion List モードが使いにくいのは、以下の点です。

  • C-f/C-b/C-n/C-pはカーソルの移動であって、候補間の移動ではない
  • RETで選ぶと、候補のリストを表示する前の状態に戻れない
    • Emacs 22では、カーソルが他のバッファに行ってしまう
    • Emacs 23では、元のバッファにカーソルが戻るが、余計なバッファが表示されたまま

という訳で、これらを解決するコードを書いてみました。最後に付けているコードを
".emacs" に入れるだけです。

こういう使い方を想定しています。

  • TAB や M-TAB で補完の候補を表示
  • C-xo で補完の候補のバッファへ移動
  • C-f/C-b/C-n/C-p あるいは C-s/C-r で候補を選択
  • RET で候補を選ぶと、元々の状態に戻り、選んだ候補が挿入される
(define-key completion-list-mode-map "\C-n" 'next-completion)
(define-key completion-list-mode-map "\C-f" 'next-completion)
(define-key completion-list-mode-map "\C-p" 'previous-completion)
(define-key completion-list-mode-map "\C-b" 'previous-completion)
(define-key completion-list-mode-map "\C-m" 'my-choose-completion)

(defun my-choose-completion ()
  "Choose the completion that point is in or next to."
  (interactive)
  (let (beg end completion (buffer completion-reference-buffer)
	(base-size completion-base-size))
    (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
	(setq end (point) beg (1+ (point))))
    (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
	(setq end (1- (point)) beg (point)))
    (if (null beg)
	(error "No completion here"))
    (setq beg (previous-single-property-change beg 'mouse-face))
    (setq end (or (next-single-property-change end 'mouse-face) (point-max)))
    (setq completion (buffer-substring-no-properties beg end))
    (delete-completion-window)
    (choose-completion-string completion buffer base-size)))

候補数の問題もないし、検索もできます。

P.S.

Mew では、フォルダ名を入力するときに、C-s/C-r/TAB を組み合わせて使うと、より快適に候補が選択できます。大昔に実装したけど、使っている人はいるでしょうか?