概要
Emacs を利用していると全部 Emacs でやりたくなるのは Emacs 使いとして当然だと思います。
Shell だって Terminal など利用せず Emacs 上で動作させたくなることでしょう。
この文書では Emacs 上で Shell を快適に利用するための設定を記述していきます。
検証環境
この文章は主に以下の環境でテストした結果を記述しています。
- Emacs
- GNU Emacs22.3
- GNU Emacs23.1
- OS
- Windows XP SP3
- Mac OS X 10.6.2 以上
- Mac OS X 10.5.8(Intel,PPC)
- Shell
- Bash 3.2.48
- Zsh 4.3.10
- Package Manager
- Cygwin 1.7.1
- Fink 0.29.10
- MacPorts 1.8.2
Warning
未検証の環境によっては問題が発生する可能性があります。どんなことでも良いので問題点に気づいたらコメントいただけるとありがたいです。よろしくお願いします。
Emacs での Shell Mode に関する基礎知識
Emacs から Shell を利用する Mode は大きく分類すると 3種類あります。
- shell
- term (ansi-term)
- eshell
それぞれに特徴があります。
shell
M-x shell で起動します。
単純な機能としては貧弱です。タブによる補完などが十分にできません。
カスタマイズ性はややすぐれていますが、Zsh と連携したり Bash の最新機能を利用しようとすると不便です。
term (ansi-term)
M-x term もしくは M-x ansi-term で起動します。term と ansi-term は同じ物です。
カスタマイズ性がややよろしく無いようですが、機能がすぐれており、Zsh や Bash と連携させるなら、このモードを利用します。
eshell
M-x eshell で起動します。
Emacs Lisp のみで実装された Shell です。shell の中で Emacs Lisp 関数を利用できり、Emacs Lisp な関数をその場で定義することができます。
Windows のように Cygwin を入れないと Bash や Zsh を利用できない環境では比較的便利です。
カスタマイズも Emacs Lisp でかなり高度にできます。
どのモードを利用するか
Bash や Zsh を利用したいので、この記事では term を利用してカスタマイズしていきます。
利用する Shell について
Bash と Zsh に対応した設定をしていきます。筆者が Zsh を利用しているため Zsh で主に検証しています。Bash では検証不十分による問題が存在する場合がありますが、その場合はご指摘ください。
Windows での Shell の準備
Windows の場合は Bash 、Zsh を利用するなら Cygwin 等でインストールする必要があります。
また fakecygpty をコンパイルしてパスの通った場所に置いておくと良いでしょう。
http://www.meadowy.org/meadow/browser/trunk/nt/fakecygpty.c
gcc -o fakecygpty.exe fakecygpty.c
cp fakecygpty.exe f_zsh.exe
cp fakecygpty.exe f_bash.exe
cp fakecygpty.exe f_ssh.exe
Mac OS X での Shell の準備
Mac OS X にデフォルトでインストールされている Zsh はマルチバイト文字が正常に扱えませんのでマルチバイト文字を利用する場合は fink もしくは MacPorts を利用してマルチバイト対応でコンパイルした Zsh を導入する必要があります。
この手順は必須ではありませんが日本語ファイル等を扱う方はインストールしておいた方が無難かと思います。
fink の場合は以下のようにします。Trees で unstable/main を有効にする必要があります。また最新情報に更新してからインストールした方が良いでしょう。
# 最新情報に更新します
sudo fink selfupdate
# zsh-multibyte をインストールします
sudo fink install zsh-multibyte
MacPorts の場合は以下のようにします。最新情報に更新してからインストールした方が良いでしょう。
# 最新情報に更新します
sudo port -v selfupdate
sudo port -v sync
# zsh-devel をインストールします
sudo port install zsh-devel +mp_completion +pcre
Bash に関しては特に問題はないはずです。
Emacs 側の設定
Emacs で Shell を正常に利用するためには Emacs と Shell の双方に設定が必要です。
Emacs の設定は $HOME/.emacs.d/init.el (旧 .emacs.el) で設定します。
PATH の設定
Mac OS X では Emacs をダブルクリックにて GUI として起動すると PATH を正常に引き継げないようですし、また環境依存性を減らすためにも init.el の中で PATH の設定をした方が無難です。
PATH と exec-path を同時に設定した方が普通の場合は使いやすいと思われますので、以下のようにして PATH を通します。
;; より下に記述した物が PATH の先頭に追加されます
(dolist (dir (list
"/sbin"
"/usr/sbin"
"/bin"
"/usr/bin"
"/opt/local/bin"
"/sw/bin"
"/usr/local/bin"
(expand-file-name "~/bin")
(expand-file-name "~/.emacs.d/bin")
))
;; PATH と exec-path に同じ物を追加します
(when (and (file-exists-p dir) (not (member dir exec-path)))
(setenv "PATH" (concat dir ":" (getenv "PATH")))
(setq exec-path (append (list dir) exec-path))))
MANPATH も設定しておくと良いでしょう。
(setenv "MANPATH" (concat "/usr/local/man:/usr/share/man:/Developer/usr/share/man:/sw/share/man" (getenv "MANPATH")))
利用する Shell の設定
どの Shell を利用するかを設定します。筆者は多数の環境を利用するため、以下のように設定して、Zsh、Bash、cmdproxy の順に探して最初にみつかった物を利用するようにしています。
f_zsh や f_bash は fakecygpty.exe をリネームしたもので、Meadow や NTEmacs で完全に Bash や Zsh を利用しようとすると必要な物です。
cmdproxy は NTEmacs に同梱されているコマンドプロンプトを Emacs から利用するためのコマンドです。
環境によって多少工夫する必要があるでしょう。
;; shell の存在を確認
(defun skt:shell ()
(or (executable-find "zsh")
(executable-find "bash")
;; (executable-find "f_zsh") ;; Emacs + Cygwin を利用する人は Zsh の代りにこれにしてください
;; (executable-find "f_bash") ;; Emacs + Cygwin を利用する人は Bash の代りにこれにしてください
(executable-find "cmdproxy")
(error "can't find 'shell' command in PATH!!")))
;; Shell 名の設定
(setq shell-file-name (skt:shell))
(setenv "SHELL" shell-file-name)
(setq explicit-shell-file-name shell-file-name)
文字コードの設定
筆者は文字コードを utf-8 に統一しています。 set-language-environment と prefer-coding-system を設定することでほぼ utf-8 になります。
(set-language-environment 'utf-8)
(prefer-coding-system 'utf-8)
term 内の文字コードは locale-coding-system にて設定すると良いでしょう。また file-name-coding-system を設定しておかないと正常な処理が実施できない場合があります。
Windows でもしコマンドプロンプトを利用する場合は sjis にした方が良いでしょう。
Mac OS X では utf-8 だと日本語のファイル名を利用すると正常に処理できなくなるので utf-8-hfs を利用します。 utf-8-hfs を利用するために必要なファイル ucs-normalize は Emacs23.2から標準搭載になります。 Emacs22 や Emacs23.1 では http://repo.or.cz/w/emacs.git/blob_plain/HEAD:/lisp/international/ucs-normalize.el 等から取得してください。
(cond
((or (eq window-system 'mac) (eq window-system 'ns))
;; Mac OS X の HFS+ ファイルフォーマットではファイル名は NFD (の様な物)で扱うため以下の設定をする必要がある
(require 'ucs-normalize)
(setq file-name-coding-system 'utf-8-hfs)
(setq locale-coding-system 'utf-8-hfs))
(or (eq system-type 'cygwin) (eq system-type 'windows-nt)
(setq file-name-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)
;; もしコマンドプロンプトを利用するなら sjis にする
;; (setq file-name-coding-system 'sjis)
;; (setq locale-coding-system 'sjis)
;; 古い Cygwin だと EUC-JP にする
;; (setq file-name-coding-system 'euc-jp)
;; (setq locale-coding-system 'euc-jp)
)
(t
(setq file-name-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)))
locale-coding-system は echo $LC_ALL 等で文字コードを確認して Terminal の locale に合せる必要がありますので環境に合せてください。
システムの terminfo を利用しない設定
Zsh を利用して term を起動すると 4m のような文字が付与されてしまう場合があります。
これは Emacs から起動した Shell では環境変数 TERM の値が TERM=eterm-color になり、eterm-color という terminfo が存在しない環境が存在するためです。
そのまま eterm-color を利用したい場合は init.el に以下を記述してください。
;; Emacs が保持する terminfo を利用する
(setq system-uses-terminfo nil)
もしこの設定をしても 4m のような文字が消えない場合は 環境変数 TERM の設定 を実施してください。
エスケープを綺麗に表示する
ls などで色が出るようにしていると Shell のエスケープ文字が表示されてしまう場合があります。これを避けるには以下の設定を init.el に記述します。
(autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t)
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
term 呼び出しキーの割り当て
毎回 M-x で呼びだすのは面倒なのでキーを割り当てると便利でしょう。
以下を init.el に記述しておくと C-c t で Shell が起動します。キーは好みで割り当てしてください。
(global-set-key (kbd "C-c t") '(lambda ()
(interactive)
(term shell-file-name)))
Shell 側の設定
どうしても Emacs の Shell の中では動作しない設定も存在します。また Terminal では必要ですが Emacs の Shell の中では不要な設定も存在しています。
処理の分岐
Shell の設定では Emacs の Shell で起動した場合と Terminal から起動した場合で処理を分岐させた方が良いでしょう。
Emacs の term を起動すると環境変数 EMACS に値が入ります。term を起動して以下で内容を確認してみると良いでしょう。
echo $EMACS
とりあえずは以下のように分岐可能です。
if [ "$EMACS" ];then
# Emacs 内で起動した時の処理
else
# Terminal から起動した時の処理
fi
Zsh では右プロンプト等が Emacs 内だと邪魔になりやすいようです。Bash や Zsh の設定は人により非常に複雑化しているので Emacs なのかを判定する以下のような関数を作成しておきます。
isemacs(){
[[ "$EMACS" != "" ]] && return 0
return 1
}
この関数を利用して分岐すると便利でしょう。
どの設定が Emacs 内の term で問題になるのかは現在調査中です。問題になった設定を教えていただけるとありがたいです。
環境変数 TERM の設定
Mac OS X 付属の Zsh を利用していたり、MacPorts を以前から利用しているユーザの場合 terminfo が正常に存在しない場合があります。その場合 terminfo を生成するか、Shell の設定にて明確に terminfo を指定してあげる必要があります。
terminfo を Emacs 本体から取得して生成した方が良いでしょう。以下のようにして eterm-color の terminfo を生成します。
# eterm-color.ti から生成した terminfo を利用する。tiファイルのパスは自分で判断して変更してください
tic -o ~/.terminfo /usr/local/share/emacs/23.1/etc/e/eterm-color.ti
# Mac OS X で app 形式の場合は以下のような場所にあります
tic -o ~/.terminfo /Applications/Emacs.app/Contents/Resources/etc/e/eterm-color.ti
terminfo を生成しても動作しない場合は以下のような設定を Shell の設定ファイルに記述すると良いでしょう。
if [ "$EMACS" ];then
export TERM=Eterm-color
fi
eterm-color を利用すると多少普段の Terminal とは挙動が異なります。もし普段の Terminal と表示の挙動を同じにしたい場合は、 以下のような設定にすると良いでしょう。
export TERM=xterm-color
TERM の値は利用している Terminal によって異なりますので、 echo $TERM して自分の環境を確認してください。
Emacs からの Shell 利用を標準以外の機能で拡張する
ここまでの設定は Emacs の標準機能ですが、標準の機能だけで快適さを追求しても個人的には満足な状態にはなりませんでした。
標準以外の機能を追加してより便利にしてみます。
multi-term.el
multi-term は term を拡張したモードになります。
term は確かに優れたモードですがいくつかの問題も存在しています。
- 複数起動ができません
- Emacs の標準的なキーを多数奪ってしまいます
- exit してもバッファが消えません
- Emacs 終了時に term 内の shell を終了していないと自動で終了してくれません
- デバッグプログラムのための専用ウィンドウを持ちません
これらを解決するために multi-term.el を利用します。
cd ~/.emacs.d
curl -O http://www.emacswiki.org/emacs/download/multi-term.el
init.el には以下の設定をします。
(require 'multi-term)
(setq multi-term-program shell-file-name)
M-x multi-term で起動します。
かなり使いやすいかと思います。
"C-z"、"C-x"、"C-c"、"C-h"、"C-y"、"<ESC>" のキーが奪われなくなりますので、ほとんどの操作は Emacs 的にできるはずです。
他のキーも奪われたくなければ以下のようにキーを追加します。
(add-to-list 'term-unbind-key-list '"M-x")
term は char mode と line mode があり デフォルトは char mode です。
multi-term の char mode では C-n で次の行に移動、 C-p で前の行に移動といった Emacs 的な動作ができ、 M-n や M-p でコマンドの履歴をたどることができます。
さらに Emacs的な操作にしたければ以下のように hook に設定を追加します。
(add-hook 'term-mode-hook
'(lambda ()
;; C-h を term 内文字削除にする
(define-key term-raw-map (kbd "C-h") 'term-send-backspace)
;; C-y を term 内ペーストにする
(define-key term-raw-map (kbd "C-y") 'term-paste)
))
また multi-term 呼びだし用にキーも割り当てておくと良いでしょう。
(global-set-key (kbd "C-c t") '(lambda ()
(interactive)
(multi-term)))
キーで起動した時に複数起動でなく既存のバッファを選択したい場合は以下のように設定します。
(global-set-key (kbd "C-c t") '(lambda ()
(interactive)
(if (get-buffer "*terminal<1>*")
(switch-to-buffer "*terminal<1>*")
(multi-term))))
multi-term 内で exit すると term との動作の違いが簡単にわかるかと思います。また multi-term を終了しないままでもう一つ multi-term を起動すると別の Shell が起動します。
multi-term-next や multi-term-prev で複数の Shell のバッファのみを切り替えることが可能です。
頻繁に利用するならキーを割り当てておくと良いでしょう。
(global-set-key (kbd "C-c n") 'multi-term-next)
(global-set-key (kbd "C-c p") 'multi-term-prev)
また elscreen を利用すれば Terminal 内での screen と似た感じで操作できるでしょう。
multi-term は初期設定のままだと日本語の入力が Shell に正しく渡りません。日本語の表示や補完には問題がなく入力だけが問題になります。日本語のファイルを作成したい場合等は Emacs の機能を利用するようにしてください。
shell-pop.el
shell-pop は shell のウィンドウを簡単に呼び出すための拡張です。
cd ~/.emacs.d
curl -O http://www.emacswiki.org/emacs/download/shell-pop.el
デフォルトでは multi-term には対応していませんが以下のように設定すると対応できます。以下の設定では F8 を押すと、 multi-term で起動した shell がフレームを分割して起動します。
(require 'shell-pop)
;; multi-term に対応
(add-to-list 'shell-pop-internal-mode-list '("multi-term" "*terminal<1>*" '(lambda () (multi-term))))
(shell-pop-set-internal-mode "multi-term")
;; 25% の高さに分割する
(shell-pop-set-window-height 25)
(shell-pop-set-internal-mode-shell shell-file-name)
;; ショートカットも好みで変更してください
(global-set-key [f8] 'shell-pop)
全部設定しても満足できない場合
term だけで全てを簡潔させることを考えず Emacs の機能を利用してみると良いかもしれません。
Emacs には以下のような機能がありますのでその利用を検討してみてください。
- FTP や SSH 等の操作は tramp を利用する
- grep は M-x grep を利用する
- M-! で shell コマンドの実行ができる
- Emacs Lisp からは (shell-command-to-string "pwd") のようにすると Shell コマンドの実行結果を文字として取得できる
変更履歴
- 2011-01-23: Emacs Lisp の誤植を修正(Thanks YMD)
- 2010-11-16: shell-pop-set-window-height の所を修正。(Thanks cyber-nanomomonga)
- 2010-04-04: ucs-normalize.el に関して取得先を追記
- 2010-03-28: MANPATH の誤植を修正
- 2010-03-27: 文字コードの設定とキー操作に関して簡単に補足を追加。
- 2010-03-26: 誤植の修正。shell-pop の設定を修正。(Thanks miurah3)
- 2010-03-24: 検証環境を追加。terminfo 回りの記述を追加。(Thanks @nanasess)
- 2010-03-22: system-uses-terminfo の値を t から nil に変更。MacPorts の Zsh における Variants の間違いを修正。(Thanks @nanasess)
- 2010-03-21: 公開
以下はゲストコメント可能です。名前とメールアドレスは任意の物を入力していただいてかまいません。 blog comments powered by Disqus