auto-complete.el が楽しい。

会社の方にうまく書けないからこっちに。

まっちゃんがテキスト入力中に補完候補を自動的に表示してくれる auto-complete.el をリリースしました — ありえるえりあなんてものを作ったわけですよ。こいつはインテリセンス的なメニューを出してくれるライブラリで、これを使うとそんなのが結構簡単に作れる。すごい楽しい。

標準だと適当に単語を拾ってくれるんだけど、以下の変数に関数を設定すると好きなように候補を選ぶ事ができる。

  • ac-find-target-function: 補完対象の文字列の開始位置
  • ac-enum-candidates-function: 補完候補を作る

というわけで、いくつか補完用の関数を作ってみた。

elisp のシンボルを補完(適当版)

こんな感じでおk。

(defun ac-lisp-enum-candidates (target)
  (loop for x in (all-completions target obarray)
        repeat ac-candidate-max
        collect x))
(setq ac-enum-candidates-function 'ac-lisp-enum-candidates)

elisp のシンボルを補完(がんばった版)

lisp.el の lisp-complete-symbol からいろいろコピる。これ系の関数がもうちょっと細分化されてるといろいと嬉しいのにね。

(defun ac-lisp-enum-candidates (target)
  (let* ((beg (ac-lisp-find-target))
         (predicate
          (save-excursion
            (goto-char beg)
            (if (not (eq (char-before) ?\())
                (lambda (sym)           ;why not just nil ?   -sm
                  (or (boundp sym) (fboundp sym)
                      (symbol-plist sym)))
              ;; Looks like a funcall position.  Let's double check.
              (if (condition-case nil
                      (progn (up-list -2) (forward-char 1)
                             (eq (char-after) ?\())
                    (error nil))
                  ;; If the first element of the parent list is an open
                  ;; parenthesis we are probably not in a funcall position.
                  ;; Maybe a `let' varlist or something.
                  nil
                ;; Else, we assume that a function name is expected.
                'fboundp)))))
    (loop for x in (all-completions target obarray predicate)
          repeat ac-candidate-max
          collect x)))

(defun ac-lisp-find-target ()
  (unless (memq (char-syntax (char-before)) '(?\' ?\( ?\)))
    (with-syntax-table emacs-lisp-mode-syntax-table
      (save-excursion
        (backward-sexp 1)
        (while (= (char-syntax (following-char)) ?\')
          (forward-char 1))
        (point)))))

(setq ac-enum-candidates-function 'ac-lisp-enum-candidates)
(setq ac-find-target-function 'ac-lisp-find-target)

abbrev してみる

確定するコマンドを変えて abbrev してみるよ。

(defun ac-abbrev-enum-candidates (target)
  (loop for x in (all-completions target local-abbrev-table)
        repeat ac-candidate-max
        collect x))
(defun ac-abbrev-find-target ()
  (save-excursion
    (and (forward-word -1) (point))))

(defun ac-abbrev-done ()
  (interactive)
  (ac-complete-1)
  (expand-abbrev)
  (ac-abort))
(setq ac-enum-candidates-function 'ac-abbrev-enum-candidates)
(setq ac-find-target-function 'ac-abbrev-find-target)
(define-key ac-complete-mode-map "\r" 'ac-abbrev-done)

dabbrevしてみる

自分のバッファ内だけで dabbrev。動作的には auto-complete の default の動作とほとんど一緒だと思う。

(defun ac-dabbrev-enum-candidates (target)
  (let ((dabbrev-check-other-buffers nil)
        (dabbrev-check-all-buffers nil))
    (dabbrev--reset-global-variables)
    (loop for x in (dabbrev--find-all-expansions target nil)
          repeat ac-candidate-max
          collect x)))
(defun ac-dabbrev-find-target ()
  (unless (memq (char-syntax (char-before)) '(?\' ?\" ?\( ?\) ?\ ))
    (save-excursion
      (dabbrev--goto-start-of-abbrev)
      (point))))
(setq ac-enum-candidates-function 'ac-dabbrev-enum-candidates)
(setq ac-find-target-function 'ac-dabbrev-find-target)