Comments
Description
Transcript
Emacs上のターミナルを最強に
Emacs 上のターミナルを最強に 伊奈 林太郎 2012-10-20 @ 関西 Emacs#x06 伊奈 林太郎 Emacs 上のターミナルを最強に 1 ターミナル使ってますか? ◮ ◮ 素のターミナル 標準的なターミナルエミュレータ xterm, gnome-terminal, Terminal.app, ... ◮ マルチプレクサ screen, tmux, ... ◮ ssh といっしょになってるもの PuTTY, Tera Term, ... ◮ Emacs 上 term.el ◮ 使ってない eshell.el, ... ◮ その他 伊奈 林太郎 Emacs 上のターミナルを最強に 2 ターミナル使ってますか? ◮ ◮ 素のターミナル 標準的なターミナルエミュレータ xterm, gnome-terminal, Terminal.app, ... ◮ マルチプレクサ screen, tmux, ... ◮ ssh といっしょになってるもの PuTTY, Tera Term, ... ◮ Emacs 上 term.el ◮ 使ってない eshell.el, ... ◮ その他 伊奈 林太郎 Emacs 上のターミナルを最強に 2 ターミナルと Emacs ターミナルエミュレータを使う理由 ◮ ◮ ncurses アプリもちゃんと動いてほしい 素の端末を触るときにパニくらない Emacs との共存 ◮ Emacs は別窓で ◮ ウィンドウが増えてうざい ◮ 端末とのコピペが面倒 ◮ screen の中で Emacs ◮ キーボードだけでコピペ ◮ Emacs ごと detach 伊奈 林太郎 Emacs 上のターミナルを最強に 3 screen のままならないところ ◮ ◮ ◮ ◮ 改造しにくい CJK ambiguous width ◮ 問題の切り分けが難しくなる (X などの) クリップボードとの連携 ◮ 面倒なハックが必要 環境変数の引き渡し ◮ 外部からのコマンド発行で解決 (要開発版) # この辺は tmux でも同じですね 伊奈 林太郎 Emacs 上のターミナルを最強に 4 すべて Emacs でやる ◮ ◮ ◮ ◮ 伊奈 林太郎 CJK, クリップボード なども OK detach もできる (emacs --daemon) Emacs 本体と連携 ⊚ ◮ 操作性を一体に Lisp で改造しまくり Emacs 上のターミナルを最強に 5 Emacs 内端末エミュレータ term.el 使い方 M-x term, M-x ansi-term 特徴 — 2 つのモード ◮ term-char-mode ◮ 打ったものがそのまま端末へ ◮ term-line-mode ◮ Emacs のバッファに近い編集 しくみ ◮ process-filter で制御シーケンスを解釈 ◮ バッファに put-text-property しながら表示 伊奈 林太郎 Emacs 上のターミナルを最強に 6 term.el のいけてないところ ◮ ◮ ◮ ◮ ◮ ◮ キーがほぼすべて端末に持っていかれる ◮ M-x とかきかない ◮ でも ESC とかどっちで認識すべき? 端末が 1 つしか開けない (内部的には可能だけどインタフェースが無い) 色が 8 色しかない term-line-mode がちょっと貧弱 コードがレガシーで拡張しにくい ◮ 関数がでかい ◮ hook も少ない 遅い 伊奈 林太郎 Emacs 上のターミナルを最強に 7 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 8 term+.el をとりあえず使ってみる ダウンロード → 真っ新な状態でのお試し $ $ $ $ git clone git://github.com/tarao/term-plus-all.git cd term-plus-all git submodule update --init make emacs # or make term # or make EMACS=emacs-snapshot term 注意点 ◮ Emacs 24.1.50 で開発してます ◮ 22 はサポートしません ◮ 23 は細かいところが不安定かも ◮ 24.2 はおそらく OK ◮ 24.3 (24.2.50) の term.el の変更には未対応 伊奈 林太郎 Emacs 上のターミナルを最強に 9 デモ 伊奈 林太郎 Emacs 上のターミナルを最強に 10 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 11 256 色対応 / xterm 互換性 (require 'xterm-256color) 256 色対応 ◮ 256 色表示の制御シーケンスの解釈を実装 ◮ ついでに斜体 , 取り消し線等にも対応 ◮ 原理的には 24bit 色に対応可能 (cf. Konsole) (24bit 色表示しようとするアプリはあるのか?) xterm 互換性 (TERM=xterm-256color) ◮ TERM=eterm-256color を定義すればよい? ◮ たいていのアプリは terminfo なんか見てない ◮ xterm を騙れば 256 色表示しようとしてくれる ◮ 騙るからには xterm 制御シーケンスを処理 (不完全) 伊奈 林太郎 Emacs 上のターミナルを最強に 12 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 13 キーバインド強化 [1/2] (require 'term+) 端末に奪わせないキーを定義 define-key term+char-map に 定義 するだけ (multi-term.el でもできますね) ◮ 定義済みのキー (M-x des-fun, term-char-mode) C-q 後続のキーをそのまま端末に渡す C-y 端末へ貼り付け M-RET 編集モード (term-line-mode) へスイッチ ESC 端末へ ESC を送る C-c 0.5 秒間何も入力がなければ端末へ C-c 直後に何か入力すればプレフィックスキー ◮ Emacs 本体で実行 (nil をマップ): M-x, M-:, C-x ◮ 伊奈 林太郎 Emacs 上のターミナルを最強に 14 キーバインド強化 [2/2] (require 'key-intercept) 後続のキーがあるかどうかで意味が違う! ESC 端末へ ESC を送る M-x ふつうの M-x C-c 0.5 秒間何も入力がなければ端末へ C-c 直後に何か入力すればプレフィックスキー 実装: key-intercept.el ◮ https://github.com/tarao/key-intercept-el ◮ プレフィックスキーにもコマンドを割り当てる http://d.hatena.ne.jp/tarao/20120427/1335527960 伊奈 林太郎 Emacs 上のターミナルを最強に 15 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 16 編集機能強化 [1/2] (require 'term+) 編集モード (term-line-mode) 中は ◮ ◮ 入力フィールド外では読取専用 ◮ SPC で選択開始 もう一度 SPC で範囲コピー → 編集モード終了 ◮ RET, ESC で編集モード終了 入力フィールド内ではふつうのバッファ ◮ ただし RET で端末に送信 ◮ ふつうの改行は C-j ◮ 別のメジャーモードにもできる e.g. シェルのプロンプトに sh-mode で入力 伊奈 林太郎 Emacs 上のターミナルを最強に 17 編集機能強化 [1/2] (require 'term+) 編集モード (term-line-mode) 中は ◮ ◮ 入力フィールド外では読取専用 ◮ SPC で選択開始 もう一度 SPC で範囲コピー → 編集モード終了 ◮ RET, ESC で編集モード終了 入力フィールド内ではふつうのバッファ ◮ ただし RET で端末に送信 ◮ ふつうの改行は C-j ◮ 別のメジャーモードにもできる e.g. シェルのプロンプトに sh-mode で入力 伊奈 林太郎 Emacs 上のターミナルを最強に 17 編集機能強化 [2/2] (require 'multi-mode-util) 入力フィールドだけ別モード ◮ あらかじめどのモードにするか指定 (後述) indirect buffer ◮ ◮ 編集モードに入ると 間接バッファ を作成 multi-mode.el http://www.loveshack.ukfsn.org/emacs/multi-mode.el ◮ multi-mode-util.el https://github.com/tarao/multi-mode-util 伊奈 林太郎 Emacs 上のターミナルを最強に 18 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 19 ログ機能 (require 'term+) term-start-output-log ◮ term.el に元からある (ほぼデバッグ用) term+hardcopy (C-c h) ◮ 一画面だけテキスト保存 (追記可) ◮ screen の:hardcopy 相当 term+start-buffer-log (C-c l) ◮ いままでの累積テキストを保存 ◮ 表示限界 (2048 行) を超えた分も保存 term+start-record (C-c r) ◮ 端末の制御シーケンスを時系列で保存 ◮ ttyrec 互換 (ttyplay で再生可) 伊奈 林太郎 Emacs 上のターミナルを最強に 20 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 21 マルチプレクサ [1/3] (require 'term+mux) やりたいこと ◮ ◮ ◮ ◮ 複数の端末をタブ表示 (tabbar.el, emux.el でもできますね) 編集モード以外のときはモードラインをタブに セッション (ユーザ/ホストの別) ごとにグループ化 同一セッションからは 1 つだけバッファ一覧に ◮ セッション内の選択中のタブが代表 ◮ 一覧中ではバッファ名ではなくセッション名 伊奈 林太郎 Emacs 上のターミナルを最強に 22 マルチプレクサ [2/3] タブグループ (require 'term+mux) 実装: tab-group.el ◮ ◮ ◮ ◮ ◮ ◮ https://github.com/tarao/tab-group-el 車輪の再発明 ◮ tabbar.el でできることはだいたいできる モードラインにも表示できる バッファをひとまとめにできる かっこいいタブ選択 UI D&D でタブ移動 伊奈 林太郎 Emacs 上のターミナルを最強に 23 マルチプレクサ [3/3] セッション管理 (require 'term+mux) M-x term+mux-new ◮ 現在のセッションで (or 選択して) 端末を開く M-x term+mux-new-command ◮ 現在のセッションで指定のコマンドを実行 M-x term+mux-remote-session ◮ ユーザ/ホストを指定してセッションを作成 ◮ シェル端末も 1 つ開く ◮ ローカルで root なら sudo する ◮ リモートなら ssh する 伊奈 林太郎 Emacs 上のターミナルを最強に 24 term+.el — term.el を強化する 主な機能 ◮ ◮ ◮ ◮ ◮ ◮ 256 色対応 / xterm 互換性向上 キーバインド強化 編集機能の強化 ログ機能 マルチプレクサ (+ マルチセッション) シェル連携強化 伊奈 林太郎 Emacs 上のターミナルを最強に 25 シェル連携 できること ◮ 編集モード ◮ 編集モードでのメジャーモード指定 ◮ バッファ内容を引き継いで編集モードへ ◮ ユーザ/ホスト/ディレクトリ通知 ◮ ファイル転送 (open / view / get / put) ◮ シェルコマンド履歴選択 ◮ マルチプレクサ ◮ タブタイトル設定 ◮ cdd (別タブの現在ディレクトリを取得) 方法 ◮ 端末内から特殊な制御コマンドを送る 伊奈 林太郎 Emacs 上のターミナルを最強に 26 シェル連携 [1/6] 編集モード M-i で sh-mode の編集モードへ (zsh) 1 2 3 4 5 6 7 8 9 function switch-to-line-mode-insert () { local buf="$BUFFER" zle kill-buffer zle -R # reset command line echo -ne "\e]51;mode;sh-mode\e\\" > /dev/tty echo -ne "\e]52;i;$buf\e\\" > /dev/tty } zle -N switch-to-line-mode-insert bindkey '^[i' switch-to-line-mode-insert 参照 https://raw.github.com/tarao/dotfiles/master/.zsh/eterm.zsh 伊奈 林太郎 Emacs 上のターミナルを最強に 27 シェル連携 [2/6] セッション情報 ユーザ名/ホスト名を通知 10 11 12 13 host=`hostname` # ホスト名 echo -ne "\e]51;host;$host\e\\" > /dev/tty user=`id -run` # ユーザ名 echo -ne "\e]51;user;$user\e\\" > /dev/tty ディレクトリ通知 (zsh) 14 15 16 17 18 19 function precmd_eterm_cwd () { local dir; dir=`pwd` echo -ne "\e]51;cd;$dir\e\\" > /dev/tty } typeset -Uga precmd_functions # これは一回だけ precmd_functions+=precmd_eterm_cwd ◮ Emacs 側の default-directory が変更される ◮ TRAMP でリモートファイルも開ける 伊奈 林太郎 Emacs 上のターミナルを最強に 28 シェル連携 [3/6] ファイル転送 20 21 22 23 24 25 26 o() { # シェルで見えてるファイルを開く -ne "\e]51;open;$1\e\\" > /dev/tty } v() { # シェルで見えてるファイルを view-mode で開く -ne "\e]51;view;$1\e\\" > /dev/tty } get() { # シェルで見えてるファイルを手元にコピー -ne "\e]51;get;$1\e\\" > /dev/tty } put() { # シェルで見えてる場所に # ファイルを選択してコピー echo -ne "\e]51;put;\e\\" > /dev/tty } function echo function echo function echo function 27 28 ◮ ◮ セッション情報を通知しておく必要あり get/put は FTP と同じ向き ◮ put するとミニバッファでファイルを訊く ◮ dired インタフェースでの複数選択も可 伊奈 林太郎 Emacs 上のターミナルを最強に 29 シェル連携 [4/6] 履歴選択 C-r で履歴選択 (zsh) 29 echo -ne "\e]51;histfile;$HISTFILE\e\\" >/dev/tty #一回だけ 30 31 32 33 34 35 36 function history-search-eterm () { local buf="$BUFFER" zle kill-buffer echo -ne "\e]52;h;$buf\e\\" > /dev/tty } zle -N history-search-eterm bindkey '^R' history-search-eterm ◮ 類似: zsh の履歴検索に anything.el を使う http://d.hatena.ne.jp/tarao/20100429/1272509893 伊奈 林太郎 Emacs 上のターミナルを最強に 30 シェル連携 [5/6] マルチプレクサ タブタイトル変更 ◮ ◮ 参考 screen の \ekSTR \e\\ 形式 tmux の \e]2;STR \e\\ 形式 https://raw.github.com/tarao/dotfiles/master/.zsh/screen-title.zsh cdd ◮ 他のタブの `pwd`に移動する ◮ オリジナルは id:secondlife さん (screen 用) http://d.hatena.ne.jp/secondlife/20080218/1203303528 参照 https://raw.github.com/tarao/dotfiles/master/.zsh/eterm.zsh 伊奈 林太郎 Emacs 上のターミナルを最強に 31 シェル連携 [6/6] カスタマイズ 定義済みの特殊制御コマンドを調べる ◮ M-x des-fun, term-emulate-terminal ◮ M-x term+control-command-list 新しい特殊制御コマンドを定義する 37 38 39 40 (require 'term+vars) (defun my-control-command (text) ...) (term+new-control-command "START " "END " 'my-control-command ) 例 41 42 43 (defun term+open (files &optional find-file) ...) (term+new-control-command "\033]51;open;" "\033\\" 'term+open) 伊奈 林太郎 Emacs 上のターミナルを最強に 32 まとめ Emacs 上でだって端末機能をフルに使いたい! ◮ ◮ ◮ 256 色対応 xterm 互換性向上 キーバインド Emacs なのをいいことに魔改造 ◮ ◮ ◮ ◮ 編集機能の強化 ログ機能 マルチプレクサをまるごと実装 シェル連携しまくり 伊奈 林太郎 Emacs 上のターミナルを最強に 33 参考 URL 伊奈林太郎. このスライド. http://up.orezdnu.org/papers/kansai-emacs/%23x06/slide/slide.pdf . INA Lintaro. term+.el のソースリポジトリ. https://github.com/tarao/term-plus-el . INA Lintaro. term+.el の emacs 側設定例. https://github.com/tarao/dotfiles/blob/master/.emacs.d/init/term.el https://github.com/tarao/dotfiles/blob/master/.emacs.d/init/tarao/term.el . INA Lintaro. term+.el のシェル側設定例. https://github.com/tarao/dotfiles/blob/master/.zsh/eterm.zsh . 伊奈 林太郎 Emacs 上のターミナルを最強に 34 おわり