Cloud9のプラグインを作ってみた

## Cloud9のプラグインを作ってみる
最近の開発は可能な限りCloud9でやってます。
(まだawsじゃない方を使ってます）

プラグインが作成できることを見つけたのでやってみます。

https://cloud9-sdk.readme.io/docs/the-cloud9-cli
公式ドキュメントを参照します。
"Create Your First Package"が途中からTodo、、、

## 環境設定
### Plugin Manager を有効化
メニューから `Cloud9/Preferences` を開き、
`Experimental/SDK` の `Plugin Manager` を on にします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/3a6ef694-11d2-98b0-b4e9-c7eb0306ecb2.png)


## プラグインのプロジェクト作成

メニューから `File/New Plugin/Empty Plugin` を選択すると、
空プロジェクトのフォルダとかファイルとか作成されます。

今回のプラグインは`ikezawa`という名前にすることにしました。
（後日なんらか関係するネタにする予定）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/1e01291d-011a-8a2a-8631-c75698bd6a85.png)

`plugins`フォルダ内のフォルダ名を変更します。
（画像は変更後です）

`plugin.js`の3行目と38行目あたりの `myplugin` を `ikezawa` に変更します。
（最後に plugin.js の全体を記載します）

## プラグイン開発

プラグインのプログラムに必要な依存を追加するために、2行目を次のように変更します。

```js
main.consumes = ["Plugin", "commands", "tabManager"];
```

|名前|説明|
|:--|:--|
|Plugin|プラグインのコンストラクタ|
|tabManager|タブを開いたり操作したりする機能を提供|
|commands|コマンドを作成する機能を提供|

使いやすいように7~9行目辺りに変数を追加します。

```js
var Plugin = imports.Plugin;
var commands = imports.commands;
var tabs = imports.tabManager;
```

### 新しいコマンドを作成

今回のプラグインを実行するトリガーをコマンドとして追加します。
Command-Shift-J(Ctrl-Shift-J)をトリガーとし、execで定義された関数が実行されます。

```js
/***** Add Command *****/
commands.addCommand({
　　name: "ikezawa_insert",
　　　　bindKey: { 
　　　　　　mac: "Command-Shift-J", 
　　　　　　win: "Ctrl-Shift-J" 
　　　　},
　　　　exec: function(){ 
　　　　　　alert("ikezawa!");
　　　　}
}, plugin);
```

### 実行可能かどうかを判断するメソッドを追加

先程のaddCommandに渡したオブジェクトに以下を追記します。

```js
isAvailable: function(editor) {
　　if (editor && editor.ace)
　　　　return !editor.ace.selection.isEmpty();
　　return false;
 }
```
このコマンドはエディタが存在して何かが選択されている場合のみ動作します。

## 実行を確認

`Tools/Developer/Start in Debug Mode` でデバッグモードを開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/3bf955a3-a74a-3c1b-7621-75efa4026603.png)

Cloud9がデバッグモードで別タブ（ウィンドウ）に新しく立ち上がります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/59277c47-79f6-77ea-eb7e-91ca1129f5ae.png)

`Open Plugin Explorer`をクリックし自分が作ったプラグイン `ikezawa` を選択すると有効化されます。

Command-Shift-Jを押すと実行されアラートが表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/b2b0dbc7-788d-c270-15f8-4e44c7ad4937.png)


### ノーマルモードでプラグインを読み込む方法

`Cloud9/Open Your Init Script`を選択します。
init.jsが開くので以下のように記述します。

```
services.pluginManager.loadPackage([
    "~/.c9/plugins/ikezawa/package.json",
]);
```
ブラウザをリロードするとプラグインが読み込まれます。

## もうちょっと書いてみる
さすがにこれだけでは面白くないので、選択しているテキスト内に`ikezawa`という文字列が入っているか判定するものを実装してみました。

```javascript:plugin.js
define(function(require, exports, module) {
  main.consumes = ["Plugin", "commands", "tabManager"]
  main.provides = ["ikezawa"]
  return main

  function main(options, imports, register) {
    var Plugin = imports.Plugin
    var commands = imports.commands
    var tabs = imports.tabManager

    /***** Initialization *****/
    var plugin = new Plugin("Ajax.org", main.consumes);
    var emit = plugin.getEmitter()

    function load() {

    }

    /***** Add Command *****/
    commands.addCommand({
      name: "ikezawa_insert",
      bindKey: {
        mac: "Command-Shift-J",
        win: "Ctrl-Shift-J"
      },
      isAvailable: function(editor) {
        if (editor && editor.ace)
          return !editor.ace.selection.isEmpty()
        return false
      },
      exec: function() {
        // フォーカスされているタブから選択範囲と行ごとの文字列を取得
        const range = tabs.focussedTab.editor.ace.selection.getRange()
        const lines = tabs.focussedTab.editor.ace.selection.doc.$lines
        // 文字列を作成
        var str = lines.slice(range.start.row, range.end.row + 1).join('\n')
        str = str.slice(range.start.column, str.length - (lines[range.end.row].length - range.end.column))
        // 結果表示
        console.log(str) //普通にブラウザコンソールに表示される
        const result = str.toLowerCase().indexOf('ikezawa') >= 0 ? 'Yes!' : 'No...'
        alert(result + '\n\n-- Your selection --\n' + str)
      }
    }, plugin)

    /***** Methods *****/



    /***** Lifecycle *****/

    plugin.on("load", function() {
      load()
    })
    plugin.on("unload", function() {

    })

    /***** Register and define API *****/

    plugin.freezePublicAPI({

    })

    register(null, {
      "ikezawa": plugin
    })
  }
})
```

修正したら、デバッグモードで開いているCloud9環境の右上にある`Reload ikezawa`をクリックしてプラグインをリロードします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/2f00ca39-aee0-d26a-0332-1d132f358a6b.png)

選択した文字列と`ikezawa`が入っているかどうかの判定が表示されるようになりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/4dee237e-78dd-b616-ea7d-013d9ae3e672.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5557/e33d67eb-0329-2c5b-79f5-e88337a30011.png)

## 感想
比較的簡単にプラグインを作ることができました。開発やデバッグがそれなりにスムーズにできるのが良いところです。

ただ、ドキュメントは揃っているようで揃ってない（記述が古かったり）するので、APIリファレンスとコンソールやデバッガとにらめっこしながら開発する覚悟は必要そうです。

引き続きさわってみて`ikezawa`の名に恥じない何かを作れたらいいなー。

昔、友人らと勢いで作ったものへのリンクをペタリ。
[「池澤」とつぶやくだけで癒されるslackチャンネル](
http://shingaki.me/web/%E3%80%8C%E6%B1%A0%E6%BE%A4%E3%80%8D%E3%81%A8%E3%81%A4%E3%81%B6%E3%82%84%E3%81%8F%E3%81%A0%E3%81%91%E3%81%A7%E7%99%92%E3%81%95%E3%82%8C%E3%82%8Bslack%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB/)