Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-10-16

EmacsのBackward Up Listの動きが気に入らない

| 22:30 | EmacsのBackward Up Listの動きが気に入らない - わだばLisperになる を含むブックマーク はてなブックマーク - EmacsのBackward Up Listの動きが気に入らない - わだばLisperになる

自分は、EmacsではLISPコード編集に限らずS式編集のキーバインドを良く使う程、S式編集のキーバインドが好きなのですが、backward-up-listの動きがどうも気に入りません。

具体的には、文字列の上で実行するとエラーになってしまうのが気に入らないポイントです。

LispマシンのエディタだったZmacs(Zwei)では、文字列の上で実行すると両端のダブルクォートを括弧と見做したような動きになります。

こっちの方が快適なのでこの動きをデフォルトにしてみたいところ。

とりあえず、Zweiはどうやっているのかソースを眺めてみることにしてみました。

(DEFCOM COM-BACKWARD-UP-LIST "Move up one level of list structure, backward.
Also, if called inside of a string, moves back up out of that string." (KM)
  (LET ((BP (IF (LISP-BP-SYNTACTIC-CONTEXT (POINT))
                (FORWARD-UP-STRING (POINT) (NOT (MINUSP *NUMERIC-ARG*)))
                (FORWARD-SEXP (POINT) (- *NUMERIC-ARG*) NIL 1))))
    (OR BP (BARF))
    (MOVE-BP (POINT) BP))
  DIS-BPS)

あまり良く分かりませんが、関数の名前からすると、どうやら括弧だけでなく、ポイントが文字列の上にあった場合のことも考えていたようです。

Emacsの実装ですが、

(defun backward-up-list (&optional arg)
  "Move backward out of one level of parentheses.
With ARG, do this that many times.
A negative argument means move forward but still to a less deep spot.
This command assumes point is not in a string or comment."
  (interactive "^p")
  (up-list (- (or arg 1))))

(defun up-list (&optional arg)
  "Move forward out of one level of parentheses.
With ARG, do this that many times.
A negative argument means move backward but still to a less deep spot.
This command assumes point is not in a string or comment."
  (interactive "^p")
  (or arg (setq arg 1))
  (let ((inc (if (> arg 0) 1 -1)))
    (while (/= arg 0)
      (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
      (setq arg (- arg inc)))))

のようになっています。

これをちょっと改造して、ポイントが文字列中にあった場合にも対応してみました

(defun zwei-backward-up-list (&optional arg)
  "Move up one level of list structure, backward.
Also, if called inside of a string, moves back up out of that string."
  (interactive "^p")
  (up-list-or-string (- (or arg 1))))

(defun up-list-or-string (&optional arg)
  (interactive "^p")
  (or arg (setq arg 1))
  (let ((inc (if (> arg 0) 1 -1))
        (in-string-p (in-string-p)))
    (cond (in-string-p
           (search-backward (char-to-string in-string-p))
           (setq arg (- arg inc))
           nil)
          ('T (while (/= arg 0)
                (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
                (setq arg (- arg inc)))))))

(define-key global-map [(control meta ?u)] 'zwei-backward-up-list)

モードによって依然としてエラーになりますが、プログラミングモード以外は文字列というものがないようなので、これはこれで良いかなということで放置。

割と快適になりました。

各Emacs系エディタでのBackward Up Listの動作

他のエディタはどういう風になっているのかなということで無駄に調べてみました

エディタ文字列中で実行された場合の動作
GNU Emacs括弧の対応でエラー
Xyzzy括弧の対応でエラー
オリジナル Emacs(tecoの実装)じっとして動かない
LispWorksのエディタじっとして動かない
Zwei/Zmacsダブルクォートの先頭に移動する
Allegro CLのIDEのエディタダブルクォートは無視して外の括弧へ飛ぶ
Hemlock/CMUCLダブルクォートは無視して外の括弧へ飛ぶ

どうも3種類位のバリエーションがあるようですね。

個人的にはやはりZweiの動きが一番好きです。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20101016