anything-dabbrev-expand.elでdabbrevの部分マッチをサポート!

anything-dabbrev-expand.elリリース - http://rubikitch.com/に移転しました

昔からEmacs Lispの長いシンボルにはうんざりしていた。最近使ったシンボルはよくdabbrevで補完するのだが、数文字打ってすぐdabbrevしてしまうと、別なシンボル名に補完されてしまいイライラしていた。

anything-dabbrev-candidates
anything-dabbrev-partial-candidates
anything-dabbrev-all-candidates

みたいに似ているものが多い。ここで「all」と打ってさくっとdabbrevできたらなぁとずっと思っていた。そこで、ついにanything-dabbrev-expand.elでdabbrevの部分マッチをサポートした。できたてほやほやの機能なんだが、俺も気に入っている!

M-x install-elisp-from-emacswiki anything-dabbrev-expand.el

を実行するか以下からもってけ!

http://www.emacswiki.org/cgi-bin/wiki/download/anything-dabbrev-expand.el

注意

カレントバッファのdabbrev部分マッチの実装にはRubyを使っているのでインストールしておくように。最初Emacs Lispでやろうとしたのだが、数百KBのファイル(rubyのeval.c)でやるとあまりにも遅すぎたので断念。
例のごとくRubyにS式を生成させて(eval (read (current-buffer)))しといた。

追記

7/1 21:00に機能追加で再アップロード。

あのままだと部分マッチの使い勝手がイマイチなので更新した。今回で「通常dabbrev→部分dabbrev→anything」の順になった。
1回 anything-dabbrev-expand を起動すると最初のdabbrevが、2回連続で起動すると最初の部分dabbrevが、3回連続で起動すると anything で選択できる。

たとえば、

quitting
keyboard-quit

と書かれているバッファがあって、最後尾に「q」と打ち anything-dabbrev-expand を起動する。
最初にdabbrevで「quitting」が、2回目で部分dabbrevで「keyboard-quit」が、3回目でanythingで選択という形になる。
anythingをC-gでキャンセルすると、最初打ち込んだ「q」が復活する。

部分dabbrevしたければ anything-dabbrev-expand を2回連続で起動しよう!連続起動しやすいように打ちやすいキーに割り当てておくべし。俺は「C-@」にしておいた。

部分dabbrev、流行るといいな。

pabbrev.elは使うのやめてる…残骸をば

最近tokyo-emacsというEmacs勉強会でpabbrev.elが話題になっているようだ。
俺は毎日EmacsWikiRSSで巡回しているから、昔からpabbrevは知っていたし、使っていた。
ソースを見てみたけど、ありゃ行儀がわるすぎる。まず、hard codingが目立ってあかん。キーバインドがTABに固定されてるし…TABってけっこうかぶってるし、相性的にまずい。ruby-electric-modeとケンカしてしまったし。まぁ、ロード順をなんとかすりゃ直るかもしれんけど。pabbrev-get-previous-bindingを再定義すれば他のキーに割り当てられる。
あと、トップレベルでdefine-keyは勘弁してほしい。ロードしただけでいつの間にか勝手にキーが割り当てられるのは気持ち悪い。関数に入れとこうよ。他のキーに割り当てたら以下を忘れずに。

(define-key pabbrev-mode-map "\t" nil)
(define-key pabbrev-mode-map [tab] nil)


で、候補選択画面が使いづらすぎ。選択時に0〜9と上段のキーを使わせるのはよくない。関数再定義でskkのようにasdf〜で選択できるようにした。

(setq pabbrev-select-keys "asdfghjkl;")
(setq pabbrev-read-only-error nil)
(setq pabbrev-idle-timer-verbose nil)
(loop for c across pabbrev-select-keys do
      (define-key pabbrev-select-mode-map (char-to-string c) 'pabbrev-suggestions-select))

(defun pabbrev-suggestions-select(&optional index)
  "Select one of the numbered suggestions."
  (interactive)
  (let ((insert-index
	 (or index
	     (loop for c across pabbrev-select-keys
                   for i from 0
                   when (= last-command-char  c)
                   do (return i))
             )))
    (if (< insert-index
	   (length pabbrev-suggestions-done-suggestions))
	(pabbrev-suggestions-insert
	 (car
	  (nth insert-index pabbrev-suggestions-done-suggestions))))))

(defun pabbrev-suggestions-buffer(suggestions prefix)
  "Form the suggestions buffer."
  (with-output-to-temp-buffer " *pabbrev suggestions*"
    (setq pabbrev-suggestions-from-buffer (current-buffer))
    (setq pabbrev-suggestions-best-suggestion
	  (car suggestions))
    (setq pabbrev-suggestions-done-suggestions
	  (pabbrev-suggestions-limit-alpha-sort suggestions))
    (setq suggestions pabbrev-suggestions-done-suggestions)
    (let
	((window-width (- (window-width) 1)))
      (save-excursion
	(set-buffer (get-buffer " *pabbrev suggestions*"))
	(pabbrev-suggestions-setup)`
	(princ
	 (concat;;"Current Word: " prefix " "
	  "Max Substring: " (try-completion "" suggestions)
	  "\n"))
	(princ
	 (concat
	  "Best Match: " (car pabbrev-suggestions-best-suggestion)
	  "\n"))
	(if suggestions
	    (loop for i from 0 to 9 do
	      ;; are we less than the suggestions
	      (if (< i (length suggestions))
		  (progn
		    (goto-char (point-max))
		    ;; insert all the suggestions
		    (let ((next-suggestion
			   (concat
                            ;; !!!!!! 
			    ;(number-to-string i)
                            (char-to-string (aref pabbrev-select-keys i))
			    ") "
			    (car (nth i suggestions)) " " ))
			  (line-length
			   (- (line-end-position) (line-beginning-position))))
		      ;; if well. are not on the first suggestion,
		      (if (and (> i 0)
			       ;; and the line will be too long
			       (< window-width
				  (+ line-length (length next-suggestion))))
			  ;; add a new line.
			  (princ "\n"))
		      (princ next-suggestion)
		      (let ((start (- (point) (length next-suggestion))))
			(overlay-put
			 (make-overlay start (+ 2 start))
			 'face 'pabbrev-suggestions-label-face))))))))))
  (shrink-window-if-larger-than-buffer (get-buffer-window " *pabbrev suggestions*")))

んだけど、候補の文字列が長いときに目視で複数の候補を見つけるのがつらいから結局使用をやめた。

anythingと連携してくれたら幸せになれそう。pabbrev-expand-maybeは次のようになっているから、(pabbrev-suggestions-goto-buffer)で選択画面にいくようになってる。で、pabbrev-expansion-suggestionsが候補のようだ。使っている人はanything.elのsourceを書けるだろう。もしかしてid:IMAKADOあたりがやってるかな?

(defun pabbrev-expand-maybe()
  "Expand abbreviation, or run previous command.
If there is no expansion the command returned by
`pabbrev-get-previous-binding' will be run instead."
  (interactive)
  ;; call expand if we can
  (if (and (eq this-command 'pabbrev-expand-maybe)
	   (> (length pabbrev-expansion-suggestions) 1))
      (pabbrev-suggestions-goto-buffer)
    (if pabbrev-expansion
	(pabbrev-expand)
      ;; hopefully this code will actually work as intended now. It's
      ;; been around the house a few times already!
      (let ((prev-binding
             (pabbrev-get-previous-binding)))
        (if (and (fboundp prev-binding)
		 (not (eq prev-binding 'pabbrev-expand-maybe)))
	    (funcall prev-binding))))))

pabbrevなくても、さっき実装したdabbrevの部分マッチがあるから俺はこれで幸せ。

追記

俺はyasnippetをスペースで起動している。勝手にsnippetが展開されることがあるけど、undoがうまく効かないのが難点。そのうち直してくれるかな。

pabbrevで候補をすぐ横に表示してくれる機能はdabbrevにも取り込みたいところ。

dabbrevはいろんな方法があるんだよね。hippie-expandとかac-modeとかdabbrev-expand-multipleとか…
dabbrevは遅いのが唯一の欠点。ボトルネックはC言語で実装してほしい…Emacs界隈でもRubyみたいに「遅い部分は拡張ライブラリで」という動きになってほしいのだが。そのためには簡単に拡張ライブラリを作成できる体制になってほしい。ライセンスが障害になっているらしいけど、PerlRubyの場合とどう違うのだろうか。

eval-bufferやeval-regionってnil返すのか

eval-bufferは常にnilを返す。evalと名前がついてるからつい評価結果を返すのかなーって思ってたが、副作用限定なのを知って愕然とした。

eval-buffer is an interactive built-in function in `src/lread.c'.
(eval-buffer &optional BUFFER PRINTFLAG FILENAME UNIBYTE
DO-ALLOW-PRINT)

Execute the current buffer as Lisp code.

「Evaluate」ぢゃなくて「Execute」って書いてるしな。そういうところがLispらしくない。それなのになぜか名前がevalとついてる。はぁ…

どんなフォント使っていても見た目は同じ…それがテキストブラウザクオリティ

http://d.hatena.ne.jp/piyo2-moko/20080701#1214913966

質問です。
うぇぶのフォントがどんなでも、るびきちさんの画面は等幅になるのでしょうか?

そう。すべてのサイトで等幅になっている。それどころか文字の大きさ、色、フォント、背景色すべて一定。サイト作成者の苦労して作ったCSSもまったく意味なし。こんなの↓

http://www.rubyist.net/~rubikitch/images/w3m-piyo.jpg

今は派手でマウスを多用するブラウザ(IEにせよFirefoxにせよ)が主流なのだが、文字情報の表示に焦点を絞ったブラウザがある。それがテキストブラウザw3mは10年愛用している。

ブラウザ比較論 - http://rubikitch.com/に移転しました