1. 概要
"tanasinn terminal emulator" は Firefox/Thunderbird/SeaMonkey上で動作する端末エミュレータです。 Windows(XP/Vista/7) + Cygwin / Mac / Linux / FreeBSD 環境で動作します。 ほぼJavascriptによる実装(2%のPython)です。 コマンドラインシェルやターミナルエディタが提供するCUI/TUIを用いて、オペレーティングシステムの 機能群にブラウザからアクセスすることができます。
2. News
2.1. 2012/05/05
Version 0.2.1.1 Supports inline Sixel Graphics. Supports UTF8/urxvt/SGR style mouse reporting. Improve performance.
2.2. 2012/04/18
Version 0.2.0.0 More precise emulation. Now it passes vttest 1, 2, 3, 4, 7, and 8. Improve performance.
2.3. 2012/04/15
Version 0.1.7.2 Important bug fix, Now it works en_US locale, sorry!
2.4. 2012/04/08
Now version 0.1.7.1 available.
-
Implement SGR blink feature.
-
Implement SGR rapid blink feature(from DOS’s ANSI.SYS).
-
Implement SGR italic feature.
-
Implement SGR halfbright feature.
重要:0.1.5.0 / 0.1.5.1はビルド時のバグのため「動きません」。 0.1.5.2は一部のプラットフォームで動きません。 いろいろ試行錯誤しちゃった人はすみません。Python2.x系のパスやCygwinのルートディレクトリなどを探しまわり、環境情報を推定しようとします。
動かなかった場合は %USERPROFILE%¥.tanasinn.js (Windows)、または~/.tanasinn.js(それ以外のOS) に、 このように書いてみてください。
process.cygwin_root = "C:\\cygwin"; process.bin_path = "/bin:/usr/bin:/usr/local/bin:/opt/local/bin"; process.python_path = "/usr/bin/python"
それでもだめな環境もあるかもしれません。 こちらからはtwitter用ハッシュタグ #tanasinn / #tanasinnが動かない あたりで探してみます。
拡張フォルダ内のディレクトリ名が歴史的理由により意味不明になっていたので、かなり変えました。
3. ダウンロード/ライセンス
Mozilla Public License 1.1 (MPL1.1) で配布しています。
4. 特色
-
Geckoベースのユーザーインターフェース (HTML Canvas + XUL)。柔軟でカスタマイズが容易です。
-
マルチプラットフォーム。現在サポートされるのは、Mac / FreeBSD / Linux(というかUbuntu) / Windows(XP/Vista/7) + Cygwin環境 (POSIX版Pythonが必要)
-
プラグインアーキテクチャ。プラグアンドプレイでのインストール・アンインストールが可能。
-
ブラウザを再起動したり閉じたりしている間、ターミナルセッションを保持します。 サスペンドしたセッションに後から再接続できます。
-
デバッガ内臓。ステップ実行やトレースができます。 ターミナルとアプリケーションがやり取りするI/Oシーケンスをリアルタイムで観察できます。
-
スクロールバック、代替スクリーン、ビジュアルベル、オーディオベルなど基本的な機能はサポートしています。
-
IMEが使えます。
-
VT52互換モード搭載。
-
Tektronix 4010/4014互換モード搭載 (一部未実装)。
-
Sixelグラフィクスモードをサポート。
-
PC端末では実装例の少ないロスト・コマンドを積極的に実装。 DECDHL/DECDWLやDRCS(Dynamically Redefined Character Set)など。
-
East Asian Width(ひらがななどの文字幅を考慮したレンダリング)に一応対応しています。 B集合以降のCJK統合拡張漢字等、サロゲートペアで表現される文字にも対応しています。 異体字セレクタ、インド系諸語等で頻出する合字やアラビア系文字の置換などの複雑なグリフ処理は、 現在主にパフォーマンス上の理由により実装されませんが、 別途プラグインで対応することも可能です。 bidiには完全に対応できていないと思います。
-
地域化のサポート。gettextのようなスタイルを採用しています。 ローカライズリソースをUI上から編集することができます。
-
Geckoがサポートする様々なエンコーディングを指定できます。
-
ウィンドウの透明化をサポート。これはブラウジングしながらターミナルで作業したい時に便利です。
-
マウスエミュレーションをサポート。xtermスタイルのノーマルレポーティング、ホイールスクロール、 UTF8/urxvt/SGRスタイルの拡張レポーティングにも対応。
-
テキストの選択や矩形選択ができます。
-
ドラッグアンドドロップやキーボードショートカットによる選択テキストのコピー・ペーストが可能です。
-
ドラッグによる移動・リサイズができます。
-
256色表示対応。32bitカラーをパレットに割り当てることができます。
-
VimperatorやKeysnailのようなコマンドラインインターフェース。
-
Vimperator/Muttator のプラグインとして導入することができます。必要なら"<C-i>"や"gF"マッピングをフックすることができます。
-
一部のプラットフォームでトラックパッドジェスチャー対応。 ピンチオープン・クローズ、スワイプ、回転を別のキーイベントにマップすることが可能。
-
スタンドアロンのXULアプリケーションとして動作させることも頑張れば可能。
5. スクリーンショット
6. 将来的にサポートされる仕様
-
エミュレーションの強化。今はとりあえずxterm系コンパチブルなエミュレーションで作ってますが、 本来はterminfoエントリを見るべきでしょう。
-
カラースキーマのサポート。16色or256色のパレットをインポート/エクスポートできるように。
-
スキンのサポート。痛端末化が可能に。
-
cursesベースのアプリーションとの連携強化。 端末アプリケーションからGeckoにアクセスしてポップアップとか動画表示とかOAuthとかやるための仕様の策定。 特別なプラグインを書かずとも端末からyoutubeを見たりtwitterやったりできるようになります。
-
プラグイン開発用ドキュメント。
7. 動作要件
-
Firefox 4.02pre+ / Thunderbird 7.0a1+ / SeaMonkey 2.1+.
-
POSIX用にビルドされたPython (2.5+, Mac、FreeBSD、Linux、 または cygwin用のもの)。 Python for Win32 や ActivePython 等はforkや仮想端末をサポートしないと思うのでダメしょう。
-
POSIX環境。 もしWindowsをお使いでしたら、C:\cygwinにCygwinをインストールしてください。
8. インストール
8.1. Firefox/Thunderbird/SeaMonkey拡張としてビルドする:
git clone git://zuse.jp/git/tanasinn.git cd tanasinn ./configure make
ビルドが成功すると、tanasinn@zuse.jpというXPIファイルが生成されます。 これをインストールしてください。
8.2. Vimperator/Muttatorプラグインとしてインストール:
Vimperator/Muttatorのランタイムディレクトリ以下にリンクを作成します。
git clone git://zuse.jp/git/tanasinn.git cd tanasinn ln -s $PWD $RUNTIME/tanasinn ln $PWD/modules/tanasinn-vimp.js $RUNTIME/plugin/
git clone git://zuse.jp/git/tanasinn.git cd tanasinn $(cygpath $COMSPEC) /c mklink /D "$(cygpath -w "$RUNTIME/tanasinn")" "$(cygpath -w "$PWD")"; ln $PWD/modules/tanasinn-vimp.js $RUNTIME/plugin/
Windowsネイティブなシンボリックリンクを作成するために、Windows Server 2003 Resource Kit Tools をインストールする必要があるかもしれません。
git clone git://zuse.jp/git/tanasinn.git cd tanasinn $(cygpath $COMSPEC) /c linkd.exe "$(cygpath -w "$RUNTIME/tanasinn")" "$(cygpath -w "$PWD")"; ln $PWD/modules/tanasinn-vimp.js $RUNTIME/plugin/
$RUNTIMEは'$HOME/.{vimperator,muttator}'のようなVimperator/Muttatorのランタイムディレクトリです。
8.3. KeySnail経由でインストール:
............
void function install_tanasinn() {
var file = "file:///…………/tanasinn/modules/common/process.js"; // <-- process.jsのパス(URL表現)
var contractID = "@zuse.jp/tanasinn/process;1";
var process_class = Components.classes[contractID]
if (!process_class) {
Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader)
.loadSubScript(file);
process_class = Components.classes[contractID]
}
var process = process_class
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
shell.add(["tanasinnlaunch","tla[unch]"],
"Show tanasinn's Launcher.",
function () {
process.getDesktopFromWindow(window)
.post("command/show-launcher");
}, {
argcount: "0",
bang: true
});
shell.add(["tanasinnstart","tst[art]"],
"Run a command on tanasinn.",
function (args, extra) {
process.getDesktopFromWindow(window)
.post("command/start-session", extra.left);
}, {
argcount: "?",
bang: true
});
} ();
............
9. 使いかた
9.1. 端末の起動
9.1.1. 拡張としてインストールした場合
Controlキーの2度押し (ctrl + ctrl) でコマンドラインランチャーインターフェースが出現します。 そこで例えば、"man man[Enterキー]" とタイプしてみてください。 ウィンドウのようなUIがブラウザウィンドウ内に現れ、manページが表示されると思います。
9.1.2. Vimperator/Muttatorのプラグインとしてインストールした場合:
アドオン版と同様、Controlキーの2度押し (ctrl + ctrl) でtanasinnが起動します。 Vimperator/Muttatorのコマンドライン上から起動したい場合は、以下のようにタイプしてください。
:tanasinnlaunch
もしターミナルスクリーンをVimperator/Muttatorから直接起動させたければ、以下のようにします:
:tanasinnstart <コマンド>
example:
:tanasinnstart emacs -nw
tanasinnにコマンドを送信したいときは、以下のようにします:
:tanasinncommand <コマンド>
example:
:tanasinncommand overlayecho Hello, World!
tanasinnにキー入力を送信したいときは、以下のようにします:
:tanasinnsendkeys <キーシーケンス式>
example:
:tanasinnsendkeys <nmode><C-z>top<CR>
9.2. 基本的な操作方法
xtermのような端末エミュレータを使ったことがあれば大体いけると思いますが、 以下のような特筆すべき仕様もいくつかあります。
ターミナルとコマンドラインテキストボックスの間でフォーカスを切り替えます。
ウィンドウの移動。
矩形選択。 (Terminal.appの真似)
フォントサイズの拡大・縮小。 (iTerm2の真似)
9.3. コマンドラインインターフェースを使う
[bold]*shift+shiftでコマンドラインにカーソルが移動します*。 これだけおぼえておけばとりあえず補完でなんとかなると思います。
9.3.1. 文字コード設定
decoder
アプリケーションの出力を解釈するための文字コード体系を設定します。
decoder [キャラクタセット・符号化方式名]
encoder
アプリケーションへの入力操作を行うときの文字コード体系を設定します。
encoder [キャラクタセット・符号化方式名]
使用可能な文字コード名はGeckoに依存します。補完で確認してください。
9.3.2. 地域化
localize
メッセージやUI要素のローカライズを行います。
localize [ロケールID] "[メッセージID]" "[翻訳済み文字列]"
[ロケールID](LCID)は日本語環境をお使いならたいていja-JPだと思います。
[メッセージID]はgettextのように英語表現になっています。 この設定は通常の永続化機構とは別の仕組みで保存されますので、 saveprofileのような保存操作はとくに必要ありません。
9.3.3. 外観の設定
fgcolor
前景色を設定します。
fgcolor [色番号] [CSS color]
[色番号]に対応する前景色パレットに、[CSS color]で表現される色が設定・適用されます。
bgcolor
背景色を設定します。
bgcolor [色番号] [CSS color]
[色番号]に対応する背景色パレットに、[CSS color]で表現される色が設定・適用されます。
色番号は0から255までの整数です。 通常の16色カラー端末では0から15までが使用されます。
fontfamily
フォントファミリを設定します。
fontfamily [フォント名]
ターミナルのフォントファミリが[フォント名]に設定・適用されます。
fontsize
フォントサイズを設定します。
fontsize [フォントサイズ]
ターミナルのフォントサイズが[フォントサイズ]pxに設定・適用されます。 単位がpixelであることに注意してください。
increase
フォントサイズを1px増加させます。
increase
数字のプレフィクスをつけて、以下のようにすると、フォントサイズが5px増加します。
5increase
decrease
フォントサイズを1px減少させます。
decrease
数字のプレフィクスをつけて、以下のようにすると、フォントサイズが5px減少します。
5decrease
9.3.4. ウィンドウ操作
up / down / left / right
ウィンドウを上下左右に移動させます。移動量はデフォルトで60pxです。 この値は、設定値moveshortcut.stepで変更できます。
数字のプレフィクスをつけて、たとえば以下のようにすると、5 x 60px = 300px 右に移動します。
5right
wider / narrower / shorter / taller
ウィンドウサイズを調整します。
数字のプレフィクスをつけて、たとえば以下のようにすると、スクリーンが5カラム拡大します。
5wider
9.3.5. blur (new!)
ウィンドウからフォーカスをはずします。
blur
9.3.6. 編集系操作
copy
選択されたテキストをクリップボードへコピーします。
copy
paste
クリップボード内のテキストを現在のエンコーダーで符号化し、端末に送信します。
paste
順次解説予定
9.3.7. マッピング管理
9.3.8. nmap
9.3.9. nnoremap
9.3.10. nunmap
9.3.11. cmap (new!)
9.3.12. cnoremap (new!)
9.3.13. cunmap (new!)
9.3.14. コンポーネント管理
lscomponent
disable
プラグインを無効化します。
disable [プラグインID]
enable
プラグインを有効化します。
enable [プラグインID]
9.3.15. 履歴管理
clearhistory
コマンドラインヒストリをクリアします。
clearhistory
9.3.16. セッション操作
kill/quit
現在のセッションを終了し、ウィンドウを閉じます。
kill
または
quit
detach
現在のセッションをサスペンドし、ウィンドウを閉じます。
detach
9.3.17. プロファイル操作
loadprofile
永続化されたセッションプロファイルをロードします。 以下のようにすると"default"という名前のセッションプロファイルが "$HOME/.tanasinn/persist/default.js" から読み込まれます。
loadprofile
もし別のプロファイルを読み込みたければ:
saveprofile [プロファイル名]
としてください。 [プロファイル名]は英数字、ドット(.)、アンダースコア(_)、ハイフン(-)が使用可能です。
saveprofile
現在のセッション設定を永続化します。 以下のようにすると現在のセッションプロファイルが"default"という名前で "$HOME/.tanasinn/persist/default.js" へ書き出されます。
saveprofile
もし別の名前で書き出したければ:
saveprofile [プロファイル名]
としてください。 [プロファイル名]は英数字、ドット(.)、アンダースコア(_)、ハイフン(-)が使用可能です。
deleteprofile
永続化されたセッション設定を削除します。 以下のようにするとセッションプロファイル"default"が削除されます。
saveprofile
もし別のセッションプロファイルを削除したければ:
deleteprofile [プロファイル名]
としてください。 [プロファイル名]は英数字、ドット(.)、アンダースコア(_)、ハイフン(-)が使用可能です。
globalload
globalsave
globaldelete
9.3.18. パネル操作
openpanel
パネルを表示します。
openpanel
closepanel
パネルを隠します。
closepanel
9.3.19. デバッグ支援
console
コンソールパネルの表示状態をトグルします。
console
debugger
デバッガパネルの表示状態をトグルします。
debugger
9.3.20. 低レベル設定操作
set
setglobal
9.3.21. 低レベルメッセージング操作
publish
tupstartメッセージを発行します。
publish <メッセージ式> <Javascriptコード>
example
publish command/report-overlay-message "Hello, World!"
9.3.22. ユーティリティ
sendkeys (new!)
指定されたキーシーケンス式を解釈し、キーイベントとして実行します。
sendkeys [キーシーケンス式]
example:
sendkeys <nmode><C-z>echo Hello, World!<CR>fg<CR>
sendkeys <PinchOpen>
source (new!)
指定されたファイルをtanasinnコマンドバッチファイルとして読み込み、実行します。
source [ファイル・パス]
import (new!)
指定されたファイル名を~/.tanasinn/batchesディレクトリから検索し、コマンドバッチファイルとして実行します。
import [ファイル名]
execcgi (new!)
指定されたファイル名を~/.tanasinn/cgi-binディレクトリから検索し、実行した結果をコマンドバッチとして再解釈し、実行します。
execcgi [ファイル名]
引数で指定されるファイルは実行可能なものであればなんでもよいです。 たとえば、
#!/usr/bin/env perl print <<EOM overlayecho Hello, World! EOM
のようにすればperlで記述できますし、
#!/usr/bin/emacs23 -nw --script (princ "enable console")
のようにすればelispが使えます。
vimperator (new!)
vimperatorにコマンドを送ります。
vimperator [command]
echo (new!)
ステータスラインにメッセージを表示します。
echo [メッセージ]
overlayecho (new!)
オーバーレイインジケータにメッセージを表示します。
overlayecho [メッセージ]
screenshot (new!)
現在のスクリーンを画像形式(png)で保存します。
screenshot [ファイル名]
たとえば
screenshot abc
とすると、{$HOME,%USERPROFILE%}/.tanasinn/screenshot/abc.pngにスクリーンショット画像が保存されます。
javascript
9.4. ユーザーディレクトリ
~/ or %USERPROFILE%/
|
+-- .tanasinn.js <-------------------------------- (1)
|
+-- .tanasinn/ <-------------------------------- (2)
|
+-- tanasinnrc <---------------------- (3)
|
+-- sessions.txt <---------------------- (4)
|
+-- desktop_profile/ <---------------------- (5)
|
+-- session_profile/ <---------------------- (6)
|
+-- persist/ <---------------------- (7)
|
+-- history/ <---------------------- (8)
|
+-- batches/ <---------------------- (9)
|
+-- cgi-bin/ <---------------------- (10)
|
+-- screenshot/ <------------------- (11)
|
+-- log/ <---------------------- (12)
|
+-- modules/ <---------------------- (13)
|
+-- process_components/ <------ (14)
|
+-- desktop_components/ <------ (15)
|
+-- session_components/ <------ (16)
|
+-- shared_components/ <------ (17)
9.4.1. .tanasinn.js
起動時(Processオブジェクトが生成されるタイミング)に読み込まれ、実行されるJavascriptファイル。
process.cygwin_root = "C:\\cygwin"; process.bin_path = "/bin:/usr/bin:/usr/local/bin:/opt/local/bin"; process.python_path = "/usr/bin/python"
9.4.2. .tanasinn/
ランタイムディレクトリ。
9.4.3. .tanasinn/tanasinnrc
セッション生成時(Sessionオブジェクトが生成されるタイミング)に読み込まれ、1行づつ実行されるtanasinnコマンドファイル。
設定例:
nmap <C-S-o> <cmode>detach<CR> nmap <C-S-i> <2-shift>blur<CR> nnoremap <C-S-z> <2-shift> cmap <C-z> <2-shift> cmap <C-s> <C-a><C-k>vimperator set!<CR> set renderer.normal_alpha=0.8 set renderer.font_size=20 set outerchrome.background_opacity=0.8 set outerchrome.background="-moz-radial-gradient(center, circle closest-side, #404040, #000)"
9.4.4. .tanasinn/sessions.txt
デタッチ中のセッションを管理するためのファイル。
9.4.5. .tanasinn/desktop_profile/
Desktopオブジェクトの設定が書き出されるディレクトリ。
9.4.6. .tanasinn/session_profile/
Sessionオブジェクトの設定が書き出されるディレクトリ。
9.4.7. .tanasinn/persist/
休眠中のセッションが永続化されて書き出されるディレクトリ。
9.4.8. .tanasinn/screenshot/
スクリーンショット画像が書き出されるディレクトリ。
9.4.9. .tanasinn/log/
ログが書き出されるディレクトリ。
9.4.10. .tanasinn/batches/
importコマンドの引数として与えられたファイル名が検索されるディレクトリ。
9.4.11. .tanasinn/cgi-bin/
execcgiコマンドの引数として与えられたファイル名が検索されるディレクトリ。
9.4.12. .tanasinn/modules/
このディレクトリ内にユーザー拡張やユーザーデータが配置されます。
9.4.13. .tanasinn/modules/process_components/
プロセスバスに接続されるユーザー拡張が配置されるディレクトリ。
9.4.14. .tanasinn/modules/desktop_components/
デスクトップバスに接続されるユーザー拡張が配置されるディレクトリ。
9.4.15. .tanasinn/modules/session_components/
セッションバスに接続されるユーザー拡張が配置されるディレクトリ。
9.4.16. .tanasinn/modules/shared_components/
デスクトップバス・セッションバス両方に接続されるユーザー拡張が配置されるディレクトリ。
10. Tips
10.1. モジュールの有効・無効を切り替えるには
コマンドラインから以下のようにタイプしてみてください。
enable <プラグインID>
disable <プラグインID>
10.2. セッションの設定を永続化・ロードするには
コマンドラインから以下のようにタイプしてみてください。
saveprofile
こうすれば現在のセッションの設定が "$HOME/.tanasinn/persist/default.js" へ書き出されるでしょう。 もし別の名前で書き出したければ:
saveprofile <プロファイル名>
これで設定が"$HOME/.tanasinn/profile/<プロファイル名>.js"に書き出されます。
この設定を再び読み込むには以下のようにします:
loadprofile <プロファイル名>
10.3. 現在のセッションからデタッチするには
コマンドラインから以下のようにタイプしてみてください。
detach
セッションはサスペンドされます。ランチャーインターフェースからこのセッションに再接続することができます。
10.4. 現在のセッションを終了するには
コマンドラインから以下のようにタイプしてみてください。
kill
10.5. Vimperator/Muttatorプラグインとしてインストールしたとき、 "<C-i>"(インプットフィールドを外部エディタで編集) と "gF"(HTMLソースを外部ビューワで閲覧) マッピングをフックするには
インプトッフィールドをtanasinn上の外部エディタで編集したければ、vimperatorrc/muttatorrcに 以下のコマンドを追加してください。
let g:tanasinneditorcommand="vim %"
この例ではvimコマンドがシステムにインストールされている必要があります。 「%」の部分はテンポラリファイルのパスに置換されます。
HTMLソースをtanasinnで見るには、以下のコマンドを追加します。
let g:tanasinnviewsourcecommand="vim +e '%'"
「%」はエスケープ済みのURL文字列に置換されます。 この例ではvimのインストールが必要になります。
10.6. Vimで現在のウィンドウにブラウザをオーバーレイで出したい
「Overlay Browser」という拡張をやっつけで書いてスナップショットビルドに入れておいたので、とりいそぎですが使用方法をご説明します。
以下のようなVim Scriptを書いてください。
function! s:open_gecko_window(src)
let nr = winnr()
let col = wincol()
let line = winline()
let width = winwidth(nr)
let height = winheight(nr)
call system('echo -en "\x1b]210;'.col.' '.line.' '.width.' '.height.' '.a:src.'\x07" > /dev/tty')
endfunction
function! s:close_gecko_window()
call system('echo -en "\x1b]211;\x07" > /dev/tty')
endfunction
command -nargs=1 OpenMozilla call s:open_gecko_window(<f-args>)
command CloseMozilla call s:close_gecko_window()
このようにして使用します。
OpenMozilla http://google.com
Vim側では、ウィンドウを閉じるとき
CloseMozilla
を呼んで自分で状態管理していただく必要があります。 まだリサイズとかアップデートを実装していませんので使いづらいと思います。
10.7. ターミナルからtanasinnに対してコマンドを送りたい
以下のような文字列を、TTYデバイスに対して送ってください。
¥x1b]220;<コマンド>¥x07
tanasinnはこれをtanasinnコマンドとして解釈し、実行します。 コマンドはtanasinnが使用しているデコーダーの符号化方式と同じものを使用してエンコードされている必要があります。
たとえば、シェルから
echo -en "¥e]220;overlayecho Hello, World!¥a"
とタイプすると、tanasinnにはコマンド「overlayecho Hello, World!」が渡ります。
10.8. キーマッピングの設定
tanasinnはVim scriptにファジーに似せた感じの書式でマッピング操作ができるコマンドを提供します。
-
nmap [置換対象キーシーケンス式] [置換後のキーシーケンス式]
ノーマルモードのマッピングを設定します。
-
cmap [置換対象キーシーケンス式] [置換後のキーシーケンス式]
コマンドラインモードのマッピングを設定します。
-
特殊なキー
-
リーダーキー
-
<Leader> - 設定値nmap_manager.mapleaderおよびcmap_manager.mapleaderの値
-
-
モードスイッチ仮想キー
-
<nmode> - ノーマルモード
-
<cmode> - コマンドラインモード
-
-
モディファイヤ2度押し
-
<2-Shift> - Shift key twice.
-
-
スワイプジェスチャイベント仮想キー(一部のプラットフォームのみ)
-
<SwipeLeft> - 左にスワイプ
-
<SwipeRight> - 右にスワイプ
-
<SwipeTop> - 上にスワイプ
-
<SwipeBottom> - 下にスワイプ
-
-
ピンチジェスチャイベント仮想キー(一部のプラットフォームのみ)
-
<PinchOpen> - ピンチオープン
-
<PinchClose> - ピンチクローズ
-
-
回転ジェスチャイベント仮想キー(一部のプラットフォームのみ)
-
<RotateRight> - 時計回りに回転
-
<RotateLeft> - 反時計回りに回転
-
-
############################################################################## # # Set Leader keys mappings # # set <Leader> set nmap_manager.mapleader="<C-s>" set cmap_manager.mapleader="<C-s>" ############################################################################## # # Gesture mappings # #for tmux nmap <SwipeLeft> <C-b>p nmap <SwipeRight> <C-b>n nmap <SwipeDown> <C-b>% nmap <SwipeUp> <C-b>! nmap <RotateLeft> <C-b><Space> nmap <RotateRight> <C-b><Space> # zoom in/out nmap <PinchOpen> <cmode>increase<CR> nmap <PinchClose> <cmode>decrease<CR> ############################################################################## # # <Leader> mode # # zoom in/out nmap <Leader>, <cmode>decrease<CR><Leader> nmap <Leader>. <cmode>increase<CR><Leader> # move window nmap <Leader>h <cmode>left<CR><Leader> nmap <Leader>j <cmode>down<CR><Leader> nmap <Leader>k <cmode>up<CR><Leader> nmap <Leader>l <cmode>right<CR><Leader> # break <Leader> mode nmap <Leader><Esc> <nmode>
11. 既知の問題
-
Windows + Cygwin 環境では起動やエミュレーションがやや遅いです。
-
キーボードがSandS(Space and Shift)環境だとspace + space で shift + shift を検出してしまいます。代替手段を用意しなければいけません。
-
NIC無効時には動きません。
-
開発版につき無駄に何回もloadScriptします。メモリ食いすぎ。
-
Python3未対応。Python2系が必要。
12. 拡張モジュール開発
12.1. tanasinnにおける「拡張モジュール」と「プラグイン」
拡張モジュールは、ファイル単位で認識され、所定のタイミングで実行されるJavascriptコードです。 Vimperatorにおけるプラグインと似たような概念です。 tanasinnにおけるプラグインは、拡張モジュールによりエクスポートされ、必要に応じてロードしたり、すきなとき にアンロードできるソフトウェア部品です。プラグアンドプレイのための一定の仕様を満たしたソフトウェア的実体、 という感じです。tanasinnバージョン0.1.5.4からは、プラグインマネージャが下図のように依存関係を追跡して 管理しますので、プラグインの動的な有効化・無効化がかなり安全に行えるようになっています。
12.2. 拡張モジュール開発に向いている人
以下のような方はぜひ拡張モジュールを書いてみてください。
-
Mozilla環境のCUI/TUI的エンハンスに興味を持たれている方
-
TUI環境のGUI的エンハンスやWebとの融合に興味を持たれている方
-
端末エミュレーションマニアでVTやTektronixやWyse端末やSixelを実装するのが好きな方
12.3. 拡張モジュール作成 初級編チュートリアル
tanasinnの基礎概念の習得からコンポーネント作成を経て、セッションプラグイン作成まで、なるべく飛ばないように 順を追って説明していきます。 注:現在、チュートリアルを書いていて、「この説明だるい、まどろっこしい、名前が良くない」と思ったところは思い 切ってプログラムの方を変更して単純化していますので、サンプルコードがかなりバージョンセンシティブ化しています。 最新版のtanasinnでお試しください。
12.3.1. チュートリアルの方針
このチュートリアルでは、簡単なtanasinnプラグインの作成過程を、なるべく平易な形で説明していきたいと思います。 初級編なので、「覚えることを最小限に」をモットーとしたいと思います。 拡張モジュールを書くためにtanasinnコアのソースをいきなり読みはじめるのはおすすめしません。 読むと精神的にやられます。 あのような書き方をせずとも、実はそこそこクリーンなJavascriptコードでプラグインを記述することができます。 記述は少し冗長になりますが総合的にみてずっと生産的です。 本チュートリアルではクリーンで単純なサンプル提示を心掛けます。
12.3.2. イベントバスの概念
チュートリアルに入る前に、これだけはどうしても触れておかなければなりません。「イベントバス」です。 「覚えることを最小限に」をふまえたうえでも、この説明だけはちょっとはずせません。 tanasinnは結合度的にかなりゆるいタイプのコンポーネントフレームワークを基盤として 構築されており、コンポーネント間のコミュニケーションは基本、同期的なメッセージ指向です。 そのメッセージ(セマンティクス上はイベントだったりコマンドだったりget関数だったりする)は、下図に示されるような 階層化されたバス上を流れています。
階層的に構築されたLANのようなものをイメージしてもらえるといいと思います。 ソフトウェアパターン的には、Observerパターンを階層化したもの、ととらえるとわかりやすいかなと思います。 このような階層において子要素を持つもの、上図においては、Process、Desktop、Sessionのようなものが、イベントを管理しています。 tanasinnハッカー達はこれを「イベントブローカー」、あるいは単に「ブローカー」と呼んでいます。 また逆にこの親要素にぶらさがっているもの、上図においてはProcess以外のノードを、「コンポーネント」と呼んでいます。 たとえば上の図でいうと、DesktopとSessionはイベントブローカー兼コンポーネントということになります。 コンポーネント「tty」はSessionというイベントブローカーを介してコンポーネント「screen」にメッセージを送ったりできるわけです。 イベントはUIウィジェットにおけるそれのようにキャプチャリングされたり、バブリングしたりすることはなく、 必要なら明示的にルーティングしてやる必要があります。 またVimperator/KeySnail使い的にはやや戸惑うかと思われますが、ブローカーはその子供(コンポーネント)に対する参照をもちません。 たとえばSessionというオブジェクトから「tty」への参照を明示的にひっぱってくることができません。 ややめんどくさいですがtanasinn全体がこのようなルールで構築されています。
12.3.3. 準備
まず、お使いのFirefox/Thunderbird/SeaMonkey等にtanasinnを導入してください。 以下の説明はtanasinn 0.1.5.4以上の環境を想定しているので、tanasinnは最新版を入れておいてください。 $HOME/.tanasinnがすでにある場合、以降の説明がtanasinnの実際の動きと食い違うことがあるかもしれませんので、 リネーム等しておくと、はまらなくてよいです。
12.3.4. サンプル1 - エントリーポイント
以下のようなサンプルを作成してください。
function main(broker) { broker.window.alert(broker); }
これを、 %USERPROFILE%¥.tanasinn¥modules¥session_components¥ (Windows) $HOME/.tanasinn/modules/session_components/ (Mac/Linux/FreeBSD) につっこみます。フォルダ(ディレクトリ)は無いと思うので作成してください。
この状態でターミナルセッションを開始してみます。 こうなります。
ここでもし余裕があればalert関数の中身を変えるなどして、いろいろ実験してみてください。 聡明な方なら以下のことがわかると思います。
-
このプラグインモジュールのエントリポイントはmainというシンボルをもつ関数。引数にはSessionオジェクトが与えられている。
-
このプラグインモジュールはセッションが開始されるタイミングで読み込み直され、変更等も反映されている。
-
chromeウィンドウオブジェクトはセッションオブジェクトのwindowプロパティでとれる。
Sessionオブジェクトはセッションバスを管理するブローカーです。 ターミナルウィンドウがひとつ立ち上がるごとに、Sessionオブジェクトが生成されています。 windowやdocument等のDOMオブジェクトがコンテキストに入ってきていないことにも注意してください。
12.3.5. サンプル2 - イベントとトピック
今度はセッションバス上を飛び交うメッセージを補足し、他のプラグインとコミュニケートしてみます。簡単です。
function main(broker) { broker.subscribe("event/before-input", function(message) { broker.notify("command/report-overlay-message", "key pressed: '" + message + "'"); }); }
下図のように、キーボードを押すたびにオーバーレイインジケータが出てくると思います。
これは、「input」というコンポーネントからメッセージを受けとり、プラグイン「Overlay Indicator」にデータを 渡しています。"event/before-input" や "command/report-overlay-message" はイベントソースを識別するた めの文字列で、「トピック」と呼ばれています。
12.3.6. サンプル3 - デバッグ環境をととのえる
つぎのサンプルにとりかかる前に、デバッグ環境を補強しましょう。 コンソールを有効化します。
enable console saveprofile
起動してみましょう。
console
すこしコードも書いてみましょう。
function main(broker) { broker.subscribe("event/before-input", function(message) { throw "an error occured !!"; }); }
なにかキーボードを押して"event/before-input"イベントを発生させるたびに、エラーが補足されます。 こうなります。
例外が自動補足されるということは、例外がコンポーネント境界を超えて伝播されないということでもあり (実際は伝播させる方法もありますが)、tanasinnは基本、エラーに対してとてもルーズな 立場をとります。こまめにコンソールをチェックして対処するというケースが多いです。 テスト機構が完成すれば事情はもうちょっとましになりますが。 さきほどconsoleを有効化しましたが、通常使用時にはパフォーマンスを下げるので無効化しておいたほうが良いです。 consoleがなくても、ランタイムディレクトリ以下のlog/tanasinn-js.logを見ればエラー等を診断できます。
disable console saveprofile
12.3.7. サンプル4 - コンポーネントオブジェクトの作成
コンポーネントを作成しましょう。 コンポーネントはプラグインの一歩手前の、プラグアンドプレイをサポートしない原始的なオブジェクトです。 tanasinnの規約によるとコンポーネントの最小要件は、以下のとおりです。
.英数字及びアンダースコア(_)、ハイフン(-)、ドット(.)の組み合せで表現されるString型のidをもつ。 .メッセージ "get/components" に対して、自分自身を返す。
コードで表現してみましょう。
function main(broker) { var plugin = { id: "sample" }; broker.subscribe("get/components", function(message) { return plugin; }); }
コンポーネントの登録に相当する部分です。 登録というよりも、コンポーネントいるかーとか、メニューアイテムいるかーとか、バスに対して訊いてみて、 だれかが反応するような感じです。tanasinnではだいたいの事柄がそんなふうに表現されています。ほとんどがメッセージです。 ただし、idやenabledというシグネチャ等を要求することもあるので部分的にインターフェース指向でもあります。
今回のサンプルは他のコンポーネントとおしゃべりするための準備だったのですが、このままだと達成感ゼロなので、 最新ビルドにはlscomponentというコマンドを入れておきました。 何もしないコマンドなのですが、補完でコンポーネントを列挙します。 これです。
今回作成したsampleが、ちゃんとコンポーネントとして認識されています。 軽く100を超えるコンポーネントからtanasinnが構成されていることがわかりますね。
----- つづく。
12.4. 拡張モジュール作成 中級編チュートリアル
tanasinnが提供する基礎的なサービスである、イベント式、遅延構築テンプレート、ローカライズ機構、フック機構等の意義と構造を説明し、それらを使用してシーケンスハンドラ、コンプリーター、補完表示ドライバ、エンコーダー・デコーダー、メニューアイテム等、実用的なコンポーネントを作成していく手法を例示します。これらのツールや概念を覚えるとtanasinn拡張を美しく優雅に書くことができますが、tanasinn以外ではまったく役に立ちません。
----- coming soon.
12.5. 拡張モジュール作成 上級編チュートリアル
tanasinn向けにデザインされたMOPシステムtupbaseの概要と、その拡張法について説明します。コアモジュールを読みたい・いじりたい人向け。デスクトップ拡張やプロセス拡張、独自端末モード拡張等についてもここで触れます。これもtanasinn以外ではまったく役に立ちません。
----- coming soon.
13. Developing materials
13.1. Hierarchical event broker pattern
13.2. Event bus
13.3. System stack
13.4. Object system
Coming soon.
13.4.1. Class
13.4.2. Processing decorated (annotated) member name
13.4.3. Attributes
persistable
watchable
listen
subscribe
sequence
command
nmap
cmap
add-hook
13.5. process.js / Plug-and-play dynamic module loading
Coming soon.
13.6. event.js / Event system
Defines class EventBroker, which is able to interpret and evaluate "Topic" and "Event Expression".
13.6.1. "Topic" Overview
In this event system, registered events is concerned by "topic" that is string variable consists of some digits and alphabets.
If you registered an event as follows:
var id = broker.subscribe(<topic>, <handler>, ....);
This event handler could be fired as following code:
broker.notify(<topic>);
The subscribe method returns an ID string. When you want to unregister handler, use it as follows:
broker.unsubscribe(id);
NOTE that this ID is NOT corresponds to a handler, one-to-one. The relation between Topic-ID is as same as that, because this event system is based on the concept of multicast delegate system.
13.6.2. "Event Expression" Overview
Event Expression indicates how the broker waits multiple events. It was given to subscriber method, that called such as:
broker.subscribe(<expression>, ....);
<expression> consists of 1 or multiple event topics and other tokens, that ruled by simple grammar. the detail of it is as below...
13.6.3. Grammer of Event Expression
IdentifierCharacter := '_' | '-' | digit | alphabet
NormalToken := IdentifierCharacter, IdentifierCharacter*
GlobToken := '{', NormalToken, '}'
| '{', NormalToken, '}', NormalToken
| NormalToken, '{', NormalToken, '}'
| NormalToken, '{', NormalToken, '}', NormalToken
GlobToken := NormalToken | GlobToken
PrimaryExpression := Token | '(', Expression, ')'
UnaryOperator := '@' | '~'
UnaryExpression := PrimaryExpression | UnaryOperator, PrimaryExpression
BinaryOperator := 'and' | 'or' | '&' | '|'
BinaryExpression := UnaryExpression | UnaryExpression, BinaryOperator, UnaryExpression
Expression := BinaryExpression
13.6.4. Event Expression Example
-
case 1.
"A"
-> it triggered when the event "A" is signaled.
-
case 2.
"A | B"
-> wait for multiple events "A" OR "B". it is triggered when one of either events is signaled.
-
case 3.
"A & B"
-> wait for both events "A" AND "B" it is triggered when both of these events is signaled.
13.7. ttydriver.py / TTY Driver
13.7.1. Module Overview
This module is assumed to be called by tanasinn’s "tty.js". First, tanasinn opens TCP channel and listen on 2 ports, [I/O channel] and [Control channel]. Next, tanasinn should call this script, with 2 arguments that is represent above-mentioned 2 channel’s port numbers. Then, A TeletypeDriver object is instantiate. it connect these channels and establish TCP connection, and finally forks new 4 processes as follows:
-
Application Process This is user-specified application process, launched by command such as the following.
/bin/sh -c 'exec <startcommand>'
<startcommand> is asked for tanasinn through the <Control channel>.
-
Writing Process This process wait to receive data from tanasinn through <I/O channel>, which is user’s input key sequence in many cases. As receiving data, the Process passes it to TTY master device as it is.
-
Reading Process This process wait to receive data from TTY master device, which is output sequence from application program in many cases. As receiving data, the Process passes it to tanasinn through [I/O channel].
-
Controlling Process This process communicate with tanasinn through [Control channel] in simple, lightweight, 7bit ascii-based protocol.
figure-1. Communication among TTY device pair, TeletypeDriver, tanasinn.
13.7.2. About [Control channel]'s protocol
Protocol Overview
-
This protocol is line-oriented. line terminator is \n (0x0a).
-
This protocol is command-based. 1 line should be interpreted as 1 command. A command is composed of 1 or multiple tokens. delimiter character is ' ' (0x20).
-
First token is opecode, represent a operation. An opecode consists of lower-case alphabetic sets ([a-z]+).
-
Tokens after opecode represent arguments. An arguments consists of multiple printable characters, that is encoded in base64 Data Encoding, defined in RFC-3548.
example 1:
xoff\n
Opecode of this command is "xoff". "\n" is line terminator.
example 2:
resize ODA= MjQ=\n
In this case, [bold]*opecode* is "resize". Arguments are "ODA=" and "MjQ=", these strings mean "80" and "24" when decoded.
13.8. builder.js / XUL dynamic construction
Accept UI-template object and convert it to a tree of DOM element.
13.8.1. UI-template overview
UI-template is JSON-style object that is described as based on the specific rule. It is to be converted to a node set of XUL/HTML/SVG elements by "Template Builder" object. Dependencies between DOM fragments are automatically resolved. You need not to take care of order for building them.
13.8.2. Examples
Example 1:
({ // <--- (1) tagName: "box", // <--- (2) flex: 1, style: { // <--- (3) backgroundColor: "red" // <--- (4) } })
It will be converted to following XUL element.
<box flex="1" style="background-color: red;"/>
Every UI-template object consists of <Element node> (1), and it is typically a tree set of <Element node>s. It always includes "tagName" property (2), and often includes <Style node> (3). <Style node> may have some CSS properties in camel-case (4).
Example 2:
({ tagName: "html:div", parentNode: "id-of-parent", // <--- (5) style: { textAlign: "center" } childNodes: { // <--- (6) tagName: "html:div", style: { fontSize: "1.5em" }, childNodes: [ // <--- (7) { tagName: "html:span", innerText: "abcde" // <--- (8) }, { tagName: "html:div", } ] } })
It will be converted as below.
<html:div style="text-align: center;"> <html:div style="font-size: 1.5em;"> <html:span>abcde</html:span> <html:div/> </html:span> </html:div>
The "parentNode" property (5) indicates at which the current node is to be set. if the type of property value was "string", it regards as node ID of the parent node. or if its type is "object", especially HTMLElement, it regards as the parent node object itself. The "childNodes" property has an effect which cascades down following <Element node> (6). If you wanted to create two or more child nodes under the same node, you should substitute an Array of <Element node>s (7) in "childNodes" property. The "innerText" property (8) creates a text node under current <Element node>.
Example 2:
({ tagName: "hbox", id: "parent", flex: 1, onconstruct: { // <--- (9) handler: function() { window.alert(this.id); } }, childNodes: [ { tagName: "vbox", id: "left", flex: 1, listener: { // <--- (10) type: "mouseover", context: window, handler: onMouseOver } }, { tagName: "vbox", id: "right", flex: 1, listener: [ { type: "mouseup", handler: onMouseUp }, { type: "mousedown", handler: onMouseDown } ] } ] })
It almost corresponds to following XUL code.
<hbox id="parent" flex="1"> <vbox id="left" flex="1" onmouseover=""/> <vbox id="right" flex="1"/> </hbox> <script type="application/x-javascript"/> <![CDATA[ var parent = document.getElementById("parent"); var left = document.getElementById("left"); var right = document.getElementById("right"); (function() window.alert(this.id)).apply(parent); left.addEventListener("mouseover", function() { onMouseOver.apply(window, arguments); }, false); right.addEventListener("mouseup", onMouseUp, false); right.addEventListener("mousedown", onMouseOver, false); ]]> </script>
The "onconstruct" property (9) defines a event function which fired when the property itself is parsed. The "listener" property (10) attaches a event handler at the current <Element node>.
14. バグレポート
バグレポートを歓迎します。 saitoha <user@zuse.jp> twitter: http://twitter.com/kefir_