わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

M-up, M-downで天の邪鬼移動

NTEmacsを使用していまして,カーソルの上下の移動を,いわゆる物理行にすべきか,論理行にすべきかというのは,悩ましい問題です.
そもそも,「物理行」「論理行」と書いて,人に通じるのでしょうか…調べると,物理行と論理行 - 永遠に未完成というのが見つかりました.呼称からして,厄介そうです.
まずその用語ですが,NTEmacsでM-x helpのあと,kそしてC-nを打ち込むと,next-lineの説明文が表示されます.

C-n runs the command next-line, which is an interactive compiled Lisp
function in `simple.el'.
(略)
If the variable `line-move-visual' is non-nil, this command moves
by display lines.  Otherwise, it moves by buffer lines, without
taking variable-width characters or continued lines into account.

これまで「物理行」と信じ込んでいたものは「display line(s)」,直訳すると「表示行」と書けばよさそうです.「論理行」については,「buffer line(s)」なのですが,「バッファ行」で妥協しますか.
それで本題とも言うべき,カーソルの移動方法ですが,前々から,Altを押しながらの上下というのが未定義なのが気になっていました.そこで,ここに,普段使うのと反対の移動方法,言ってみれば「天の邪鬼移動」を割り当てることにしました.
Emacs Lispのコードです.

;; line-move-visualがnon-nilのとき
;;  next-line (C-n, down), previous-line (C-p, up)は表示行移動
;;  next-line-visual (M-down), previous-line-visual (M-up)はバッファ行移動
;; line-move-visualがnilのとき
;;  next-line (C-n, down), previous-line (C-p, up)はバッファ行移動
;;  next-line-visual (M-down), previous-line-visual (M-up)は表示行移動
(setq line-move-visual t)
(defun next-line-visual (&optional arg try-vscroll)
  "Move cursor vertically down ARG lines.
If the variable `line-move-visual' is nil, this command moves
by display lines.  Otherwise, it moves by buffer lines."
  (interactive "^p\np")
  (or arg (setq arg 1))
  (setq line-move-visual (not line-move-visual))
  (next-line arg try-vscroll)
  (setq line-move-visual (not line-move-visual)))
(defun previous-line-visual (&optional arg try-vscroll)
  "Move cursor vertically up ARG lines.
If the variable `line-move-visual' is nil, this command moves
by display lines.  Otherwise, it moves by buffer lines."
  (interactive "^p\np")
  (or arg (setq arg 1))
  (setq line-move-visual (not line-move-visual))
  (previous-line arg try-vscroll)
  (setq line-move-visual (not line-move-visual)))
(global-set-key [M-down] 'next-line-visual)
(global-set-key [M-up] 'previous-line-visual)

振る舞いを箇条書きで表しますと,

  • line-move-visualがnon-nilのとき
    • next-line (C-n, down)は表示行で下移動(既存)
    • previous-line (C-p, up)は表示行で上移動(既存)
    • next-line-visual (M-down)はバッファ行で下移動(新規)
    • previous-line-visual (M-up)はバッファ行で上移動(新規)
  • line-move-visualがnilのとき
    • next-line (C-n, down)はバッファ行で下移動(既存)
    • previous-line (C-p, up)はバッファ行で上移動(既存)
    • next-line-visual (M-down)は表示行で下移動(新規)
    • previous-line-visual (M-up)は表示行で上移動(新規)

コードは複雑そうに見えて実は極めて単純で,line-move-visualの値(論理値)を反転させてから,next-lineなりprevious-lineなりを実行し,再度,line-move-visualの値を反転させるというだけです.なお,「arg」は,M-5 M-upとしたとき5行分の移動をできるようにするのに必要です.
コードの大部分は,next-lineの定義の借用です.ヘルプでnext-lineの説明が出ているバッファの,「simple.el」のところにカーソルを合わせて,Enterキーを押せば,simple.elのnext-lineの定義部が表示されます.そのコードを参考にして,天の邪鬼移動を~/.emacsに記述しました.
最後の最後に悩んで,上述のとおり「(setq line-move-visual t)」とし,普段使う移動方法には表示行を選びました.
特別な定義はしていませんが,S-M-upやS-M-downで,天の邪鬼移動をしながらリージョンの拡大・縮小もできます.