onliner-el #1

amt 『はじめまして amt と申します。

vi の !(外部コマンド)相当機能ですが、その後少し機能拡張
したものを、下で公開致しました。

http://amt.ty.land.to/MySoft/oneliner-el.html

ご指摘の点の回答もさせていただいております。

こちらの方の御意見も頂戴できれば幸いです。』 (2006/12/13 08:24)

ということで、見てみた。とりあえず Web のほう。

shell-command-on-region(C-1 M-|) とどう違うんですか?

shell-command-on-region() は、カレントリージョンを書換えるだけなので、これも、カレントバッファ全体を書換えたい時には不便かつ危険な道具です。

カレントリージョンを書換える時の基本機能は oneliner-el の同等コマンドと同じですが、コマンド実行失敗時のケアなど、人間が対話的に使うことを想定していない設計になっていると思います。但しプログラムから呼出す時は、shell-command-on-region()で十分だと思います。

対話的に使うときは、これからは oneliner-process-region/oneliner-process-region-via-shellを使いましょう。

ええと。shell-command-on-region 自身は M-| であって、C-1 ってのは単なる prefix argument なんですけど。もしかして、prefix argument を知らないのだろうか。それとも承知の上でこう書いている?
shell-command-on-region が危険ていうのも良く分からないなぁ。別に Undo 一発で元に戻るんだけどな。

リージョンを得るのに、(interactive "r") を使っていないのはなぜですか?

(interactive "r") は、マークを設定していないとエラー終了してしまいます。

マークが設定されていない時は、カレントポジションに、長さゼロのリージョンがあるように動作するのが、人間の直感が期待する動作だと思いますが、そう設計されていません。これは駄目なデザインだと思います。

また、これを interactive() 中に記述すると、リーダビリティが悪くなってしまうので、僕はリージョンの獲得に interactive() は使わないことにしています。

駄目なものは駄目なのです。

mark が設定されていないときは長さ0のリージョンが選択されているように扱うのが直感的?じゃあリージョン選択無しで kill-ring-save すると kill-ring の先頭は空になるのを期待するの?もともと違うものを同じ様に扱われると激しく気持ち悪いと思うけどなぁ。長さ0のリージョン選択なんて C-Space 一発で終わりなんだし、mark が active じゃ無いときは素直をエラーにしてくれたほうが嬉しいんじゃないかな。
あと、C-0 M-x transient-mark-mode とかやると、いちどバッファで mark を設定したら普通には mark 無効にならないわけで、常にどこかしらリージョンが選択されている状態だったりして、リージョンを選択するというアクションがない。しかも昔から Emacs を使っている人にはこっちのほうが普通。
まぁ、その辺の UI の話は水掛け論になりそうだからスルーするにしても、interactive を使えといったのは別に楽をするために (inteacrive "r") としろといったわけでなくて、単に再利用性の点で難があるという話で。実際のソースではなんか範囲を取得する関数を渡す設計になっているみたいだけど、Closure のない(というより Lexical Scope 自体がない) Emacs Lisp だとその設計はちょっと使い難いよね。で、まぁ、この仕様なら普通はこうするんじゃないかなぁ。

(defun onelinear-process-region (start end cmd)
  (interactive 
   (append
    (if mark-active (list (region-beginning) (region-end))
      (list (point) (point)))
    (list (read-string "Shell command: "))))
  ....)

(defun onelinear-process-buffer (cmd)
   (interactive
     (list (read-string "Shell command: ")))
  (onelinear-process-region 1 (1+ (buffer-size)) cmd))

別に、mark、point、max、min を組み合わせなくても region-beginning と region-end でいいよね。まぁ、複数箇所に同じようなことを書くのもアレだから実際には interactive の中身をもう少し関数に分割するだろうけど。
中身については後で。というわけで続く。