Windows で Emacs 内部 shell をストレスなく動かす = Cygwin + sshd + XMing + VMWare + Ubuntu + Emacs + Tramp + shell-mode

たまには殺伐とした噺もいいでしょう。

WindowsEmacs 内部 shell をストレスなく動かすには?

結論から言うとそんなもんねえ。
でもそれじゃ余りに何なので、この三ヶ月間で私が泣きながら辿り着いた方法をご紹介しよう!

Cygwin + sshd + XMing + VMWare + Ubuntu + Emacs + TRAMP + shell-mode

です。病的だけどちゃんと動きます。

Emacs の shell-mode が好き

長年の習慣で Emacs を使っています。別に宗教入ってる訳じゃなくて、色々便利だし、慣れてるから。
Emacs には shell-mode (M-x shell) というのがあって、 Emacs 内部で interactive shell が立ち上がる。履歴は全部バッファーに残るし、コピペも Emacs 内でできるから便利。もちろん皆さん使ってますよね?
と思ったら、使ってない。今の職場で使ってるのは俺だけだし、前の職場でも見たことない。何だかみんな Emacs の横に xterm とか開いてそこでコンパイル作業しています。エラーメッセージとかはスクロールさせて頑張って読んでる。 shell-mode ならもっと楽なのに! というか、 compilation-mode 使えよ、え、俺の使ってるコンパイラじゃエラーメッセージ取れないから役に立たない?じゃあ、自分で書いたらイイノニネ。軟弱者が。
はい。これでも宗教入ってる訳じゃなくて色々便利だし、慣れてるだけです。
え、 vi/vim ですかぁ、 Rogue 系は NetHack 散々遊んじゃったし。今更斜め移動できない Rogue 遊ぶ気になれないですよ、、、Grid bug やないっちゅーねん。
まあ、とにかくだ、俺は Emacs の shell-mode が好きで、これが無いと気持ちよく仕事できない。異常。もとい、以上。

Cygwin では上手くいかない、、、

前職の開発は Linux 100% なんですが、今度の環境は Linux + Cygwin の両方。デスクトップは「天麩羅いやざんす」とか言うので XP しか使えません(まあ、 Vista の管理したくないよな)。と言う訳で当然ながら Cygwin です。
で、当然のごとく Emacs + shell-mode を Cygwin で使おうとしたらこれが使えない:

  • コマンドを殺せない (C-c C-c)
  • コマンドをサスペンドできない(C-c C-z)

これはキツい。まるで、 unix 演習で学生が作った shell で仕事をするような辛さ。みんなはどうしているんだろうと思って同僚に聞いてみた:

shell-mode って何それ?

もういい、君らには頼らん。

問題点は、 Cygwin のシグナルの扱いが普通の unix とはちょっと違うみたいで、Emacs の shell-mode というか、comint というか、subprocess 周りはその違いには全く気を遣っていない、ということです。まあ、気を遣う義理もない訳ですが。

目標

Cygwin 環境というか、XP のデスクトップで*俺が*ストレスなく interactive shell を Emacs 内で使う方法。気分良く仕事できれば方法は何でもいい。
そして、転職以来、この目標を目指して三カ月。ようやく、上の結論に達した訳です。そこに至る過程を御紹介します。もし、何かいい方法があったら教えてくださいお願いします。

Cygwin/Emacs で頑張ってみる

まず、 CygwinEmacs 内部だけでなんとかならないかと思って頑張ってみました。
え? CygwinEmacs なんか使えねぇよ、終了(C-x C-c)さえできないじゃん?だって?そんな軟弱なレベルの人は CYGWIN=tty emacs で出直してきてください。終了後 reset は忘れずに。

eshell

eshell は elisp で書かれた Emacs 内シェル実装。まずはこれなんかどうだろと使ってみました。結果:

  • コマンドは殺せる :-)
  • サスペンドできない :-|
  • リダイレクト使えない X-(
  • いつもの shell と違う X-O

サスペンド出来ないのは痛い。ウェブで見るとサスペンドできないけど、 rename-uniquely してから、新しい eshell バッファを立ち上げれば、いいじゃん、という提案がありましたが、そんな前進しつつ退却するようなムーンウォークは許さん。他にもリダイレクト使えないとか、別の shell なので、文法が違うのも困ります。
じゃあ、 eshell 内部で bash とかを使えばどうだろうと思いましたが、またもやシグナル扱いが変でまともに動きませんでした。
結論:却下。

term-mode / ansi-term

次に試したのが term-mode もしくは ansi-term という、 shell じゃなくて、ターミナルをエミュレートするものです。
M-x term-mode (M-x aisi-term でも同じ)で立ち上げた後にまずビックリするのが、

キーバインドが訳分からなくなってしまった!!

これです。term-mode (ansi-term でも同じ) では char mode というのと line mode というのがあって、デフォルトは char mode。 char mode では C-x 以外の多くの Emacs の特殊キーは Emacs には解釈されず、そのままターミナルへ送られるのです。これを知らないと、 Emacs 狂ったとしか思えない状況になります。で、char mode では、

これは良さげ!! でも、キーが奪われるのがキモい。いわゆる shell-mode のようなキー感覚にするには line mode にするのがよいようなので、そうしてみた (C-c j)。さて、これで、殺せるし、サスペンドできるし、完璧だな!と思った訳です。そしたら、

なんだか Cygwin の問題が line mode になると立ち上がってくるようで、残念です。
普段は line mode にして、C-c C-c / C-c C-z の時だけ char mode にしてなんとかするとか、いろいろ涙ぐましい努力を elisp でやりましたが、それでも line mode をメインで使っているとコマンドラインに妙なゴミが溜まったり、いろいろと問題が続き…
結論: 使えない。というか疲れた。

Cygwin が悪いんだから他の Emacs ならなんとかなるんじゃないか?

そうです。 Cygwin がいけないんです。じゃあ、他の Emacs ならいけるんじゃないかとおもいました。

NT Emacs

Windows native の Emacs です。この shell-mode で Cygwin の /bin/bash を動かしてやるというのをネットでみました。試してみた:

結論: 意味ないじゃん。アンインストールして終了

Meadow

宮下さん(お元気ですかー!)には何の悪意もないのですが、出来れば linuxwindowsEmacs lisp のバージョンは同じにしたいのです。で、 shell-mode は同じように問題があったように記憶しています。
結論: 検討してちょっとやって、諦めた

Xyzzy

Meadow と同様の理由で却下

XEmacs

XEmacs は Cygwin でも入る。同僚の一人も使っています。昔使ったころは Emacs よりイケてた。これは、どうかな?

Windows 環境においては XEmacs の shell-mode は Emacs の問題が全くないようです。しかし、純正 Emacs とはかなり内部が変わっていて、 .emacs の設定から、 elisp の書き方とかも違う。ちょっとこれは頂けない。二つの Emacs のために設定を 2バージョンもしくは分岐して 2ケース用意して管理するほど体力ありません。Elisp でいくつかソフトも自作してるし、その移植なんかしたくないヨ。
結論: 最悪 XEmacs にすれば、なんとかなる、という最終避難所は見つけた
ああ、 Cygwin/XEmacs は X が動いてなくても GUI で立ち上がるというすごいエディタです。これは感動した。でもフォント選択がおかしいのは悲しかった。(X で動かすとちゃんと選べます)

連戦連敗

もう正直毎日業務終わってから Emacs の変な問題回避方法ばっかり考えていて頭がどうかなりそうでした。何やってもダメ。ネットで検索してもパッとした答がない。同僚も使って無いので当てにならない。しょうがない、いちいちマウスを使って、ターミナルと Emacs の間を往復するしかないのか、と思ったときもありました。何で Linux で仕事できへんのや、 Linux 環境さえあればさっさと業績出したる、環境に足を引っ張られるようではどもならん、と思っていたとき、思いついた。

VMWare + Linux(Ubuntu)

Cygwin は諦めて、 Linux で仕事すりゃいいじゃん

業務では Linux サーバ用にもシステムをコンパイルしています。そのための Linux サーバがあるのですが、距離的に遠い、他の奴がビルドとかしてると遅い。じゃあ、自分の XP に Linux の仮想環境を入れて、そこで仕事したらどうだろう。(Linux をじかにインストールするのは天麩羅いやんす的にダメなんです…お客様相手の大手にはそこら辺に限界がありますね。) Linux でやれるだけやってから、最終コンパイルCygwin でやりゃいいんじゃないか、と思いついて、 Linux (Ubuntu) をインストールしました。別に Ubuntu である必要はないんですが。

coLinux にはしなかった

coLinux、そして Portable Ubuntu も検討しましたが、 まず、安定してなさそうなのと、 Ubuntu 10.4 がさっと入る環境じゃなかったので諦めました。自分の趣味だったら VMWare より軽そうだし、そっちの方向に行ったと思いますが、業務なのでそんな設定祭りで半年とか遊んでたらまずいっしょ?

XMing

VMWare のルート全開はまずい

何がまずいって、目立ちます。普通の XP のバックグラウンドは会社指定の壁紙しか使えないようになっているから、何か妙な事をしている気分になってくる。別に何もやましいことはしてないのですが、妙な人が見つけて妙に気にすると妙な事になって VMWare 禁止とかなるとこちらも妙な人間ですからブチ切れて妙な事になりかねない。あと、VMWare のルートをがあぁっと開いていると、社内メールとかチャットとかのアップデートが見えないんですよね、、、そこで、VMWare の X クライアントを XP 側の X サーバに表示させることにしました。

Cygwin/X は何かおかしかった

まず、 Cygwin を使っていますから当然 Cygwin/X です。でも、何か会社の環境だとおかしいのです。GUI のマウスとか、キープレスのイベントが妙な遅れでサーバに伝わる、、、なんだかイベントキューのバッファリングがおかしいみたい。糞なアンチウイルスのせいかとも思いましたが、面倒なので追求しませんでした。この現象は会社で 1.8.x の xorg-server を使ったときに発生しました。 1.7.x ではなぜか発生しないのでそちらを使ってもいいし、

XMing なら大丈夫だった

なんか気味悪いので、Mingw 系の XMing を使ったら問題ありませんでした。なんでか?知らん。動けばそれでよい。

と言う訳で、私の XP のデスクトップで動いている EmacsVMWareLinuxEmacs になりました。

ssh 越しなら、shell-mode でも大丈夫!!

Linux で開発が一段落したら、 commit して、 Cygwin へ移動、 pull してコンパイルしていたのですが、別に Cygwin のウィンドウに移らなくても、 Cygwin 側に ssh すればいいじゃない?と気がつき、 Cygwin 側で sshd を設定。しかしここに罠が。

Cygwinsshd でちょっとはまる

一見ログインも出来、普通に unix コマンドなども動くので ssh 越しにコンパイルスクリプトを動かすと意味不明な "fd 0 initialization failure for ttyX" とかいうエラーが。机を蹴ったりしましたがもちろん状況は改善されず。しばらく調べていると、 sshd サービスを local admin で動かすのではなく、私のユーザー権限で立ち上げればよい事がわかりました。

shell-mode + ssh で殺したりサスペンド出来る!!

さて、 Cygwin 側への ssh も通って、 LinuxEmacs の shell-mode から、 Cygwin 側でコンパイルなどしばらくしていたのですが、ストレスが無い。気持ちよく仕事していて、ふと我に返りました:

kill(C-c C-c) と suspend (C-c C-z) が動いている!!

あまりに当然過ぎて気づかなかったのですが、今まで問題だった shell-mode での kill + suspend が両方共問題なく動いているではないですか!!問題は Cygwin(やWindowsの) Emacs の shell-mode にあったので、その shell-mode ではなく、 Linux 側の shell-mode ならば大丈夫なのは、後になって思えば、十分ありうる事でした。しかしほんとにしばらく気づかなかったヨ。

仕上げは Tramp mode

昔々、 FTP がまだ全盛だったり、 HTML を手で書いてからマニュアルで ftp 接続してサイトにアップロードしていた時代、 Ange-ftp という Emacs 内で ftp コマンドを動かして、サイトのファイルを編集するという機能がありましたが、 Tramp mode はその機能拡張版。 ssh 越しのファイルを編集できたり、 shell-mode と組み合わせて、リモートの ssh セッションを shell-mode 内に実現したり出来るのです。これを見つけたので、早速今までのアプローチに組み込みました。
Tramp を使った shell-mode では絶対パスでの cd をした場合 Tramp 側でのディレクトリ追跡が出来なくなる(M-x cd で回復可能)という問題はありますが、ローカル、リモートのファイルや shell を一つの Emacs 内で扱えるのは非常に気分が良い物です。

では、まとめ。

Cygwin/Emacs の shell-mode は kill や suspend が使えないので、絶望的な状況に追い込まれましたが、三ヶ月間の努力の末、

Cygwin + sshd + XMing + VMWare + Ubuntu + Emacs + Tramp + shell-mode

で問題を解決できました!! Cygwin でやるまでもない事は Linux で出来るというおまけつきです。VMWare + UbuntucoLinux に変えてもイケるはず。兎に角、 Windows 系の Emacs は捨て去る。これが鍵。でももしもっといい方法があったら教えてください。

他にも思いついたこと

screen コマンドでターミナルを割って、 Emacs と shell を動かせばまだ耐えれるかと思ったけど、試してません。でも screen と Emacs の二つのキーバインドを同時に混ぜて俺に自在に使えるかどうか、、、無理だろ。