Eclipse Orion 9.0 シェルコマンド追加

# はじめに
Orionには、[GCLI](https://github.com/joewalker/gcli)をベースにしたターミナル機能がデフォルトで搭載されています。
Orionシェルにはlsやcdといった、いくつかの基本的なコマンドが用意されているほか、プラグインによってユーザ定義のコマンドを追加することもできます。
今回は、Orionシェルへのコマンド追加方法を中心に説明します。
プラグインの開発・導入方法はこちらをご覧ください [Eclipse Orion 9.0 環境構築〜プラグイン開発・導入](http://qiita.com/sashim1343/items/75767ddac84b6a254e18)

# 関連するサービスタイプ
シェル機能周りのプラグインに関連するサービスタイプは次の2つです。 

- orion.shell.command : コマンドを定義する
- orion.shell.type : 独自のコマンド引数型を定義する

特に重要なのはorion.shell.commandで、コマンドの名前や動作、引数などの定義を行います。
orion.shell.typeは、組み込み型以外のユーザ定義型を使いたいときに使用します。

## orion.shell.command
### プロパティ
構成するフィールドは次のとおりです。

- name : コマンドの名前。コマンドとして入力する文字列を設定する
- description : コマンドについての簡単な説明
- manual : descriptionより長い説明(任意)
- parameters : コマンドが受け取る引数リストについて定義する(パラメータオブジェクトの配列) (任意)

個々の引数について定義するパラメータオブジェクトは、次のフィールドをもっています。

- name : データを参照するためのキー。データをargs.nameのようにして取得できる
- type : 引数の型。string, boolean, number, array, selection, file, blobの組み込み型と、orion.shell.typeで定義した型のどれか1つを選択
- description : 引数についての説明
- defaultValue : 省略したときにセットされる値。これを設定すると引数の扱いがOptional(任意)になる

typeの設定についてですが、selection, fileなどは単純に文字列で指定することができません。
これについては後述。

### 実装部分
構成するフィールドは次のとおりです。

- callback(args, context) : コマンドの動作を定義する

また、各引数は次のデータを保持しています。

- args : 入力された各引数の中身。データにはargs.nameのようにアクセスする
- context : context.cwdにシェルのカレントディレクトリ情報が格納されている。これはシェルページのURLの#以降の文字列と同じ

コマンドを打つと、args, contextに適切な値が設定された状態でcallback()メソッドが呼ばれます。
このメソッド内で何らかの処理を行い、結果をシェルに返します。
callback()メソッドの戻り値は次のいずれかです。

- string : 出力する文字列。文字列中の[テキスト]\(URL\)はリンクになります
- file : ファイルオブジェクト(後述)
- blob : {blob: blob}
- orion.Deferred : 非同期処理するときに利用。長くなるので今回は割愛

一番良く使うのはstringかと思います。

## orion.shell.type
### プロパティ

- name : 定義した型を参照するためのキー。orion.shell.commandのプロパティ"type"で使用する

### 実装部分

- parse(arg, typeSpec, context) : 入力中の文字列を解析し、引数の入力補完を行うメソッド
- stringify(object, typeSpec) : 引数のオブジェクトをシェル上での表示に適した文字列表現に変換するメソッド(任意)

ひとまずparse()メソッドだけ実装しておけば十分です。
私は今のところ、stringify()が必要になる場面に遭遇していません。
parse()の各引数が保持するデータは、次のとおりです。

- arg : パラメータとして入力中のデータについて格納。3つのフィールドprefix, suffix, textをもつ
- typeSpec
- context : {lastParseTimestamp: number} 非同期処理が絡むときに使う

戻り値はorion.Deferredまたは次のフィールドをもつオブジェクトのいずれかです。

- status : 0(マッチ), 1(部分的にマッチ), 2(有効な値にマッチしない)のいずれか
- message : マッチしなかったときに表示されるメッセージ(任意)
- predictions : 有効な補完候補 {name: string, value: object}の配列
- value : 入力が確定したらその値。そうでなければundefined

# サンプルコード
http://wiki.eclipse.org/Orion/Documentation/Developer_Guide/Plugging_into_the_shell#Example

# ハマりやすい引数型の設定
## selection
selectionはいくつかの選択肢の中から1つを選ぶ型です。
設定の際には、プロパティのtypeを次のように指定します。

```js
type: {
    name: "selection",                    // selection型を使う
    data: ["hoge", "piyo", "foo", "bar"]  // 選択肢
}
```

## file
file型の引数としてセットされるデータ(ファイルオブジェクト)は、一般的には次のフォーマットをしています。

```js
{
    path: string,  // ファイルまでのパス(シェルのカレントディレクトリからの相対パス)
    isDirectory: boolean,  // ディレクトリか否かを示す
    blob: blob             // ファイルの中身
}
```

……が、得られる項目はオプションの設定次第で変わります。
しかも、デフォルトのままでは**pathしか得られません**。
さらに、**ファイルが存在することすら確認してくれません**。
なので、file型を使う際は**必ずオプションを設定**しましょう。

```js
type : {
    name: "file",     // file型を使う
    // 以下のオプションは全て省略するとfalseとみなされる
    directory: true,  // ディレクトリの選択可
    file: true,       // ディレクトリ以外のファイルを選択可
    multiple: true,   // 複数ファイルも選択可
    recurse: true,    // サブディレクトリのファイルも再帰的に選択
    exist: true,      // ファイルが存在するか確認する
    content: true     // ファイルの中身をblobに格納する
}
```

# サブコマンドの実装
コマンドによっては、git commitのようなサブコマンドをもつものもあるかと思います。
このようなコマンドをOrionシェルに追加する方法は次のとおりです。

1. 親コマンド(e.g. "git")を、実装部分を空にして登録する
2. サブコマンド(e.g. "git commit", "git add", ...)を普通に登録する

これでサブコマンドを登録できます。
親コマンドを打った後にサブコマンドのリストを出して入力補完を行いたい場合について。
サブコマンドを列挙したselection型の引数を親コマンドの引数に設定すれば実現できます。

# 参考
Orion/Documentation/Developer Guide/Plugging into the shell - Eclipsepedia - http://wiki.eclipse.org/Orion/Documentation/Developer_Guide/Plugging_into_the_shell
joewalker/gcli · GitHub - https://github.com/joewalker/gcli
Eclipse Orion 9.0 環境構築〜プラグイン開発・導入 - http://qiita.com/sashim1343/items/75767ddac84b6a254e18
Orion 2.0: What&#8217;s New for Shell page plug-ins | Orion News - http://planetorion.org/news/2013/02/orion-2-0-whats-new-for-shell-page-plug-ins/