AtomエディタのInitファイルでコマンドを登録する

# はじめに

Atomエディタにパッケージを作るまでもないが良く使う自作コマンドをinitファイルを使って登録する方法をまとめてみます。
個人的にCoffeeScriptは覚える気にならないのでJavaScriptを使います。

# initファイルを開く

まずは、
`File` -> `Init Script...`
でInitファイルを開きます。
JavaScriptで記述する場合は、開かれたファイルの拡張子をjsに変えて名前を`init.js`として保存します。

# 関数定義

まずは関数定義です。
`init.js`に、JavaScriptの関数を通常通り定義してください。
(後述しますが、わざわざ関数定義などしなくても関数式を直接コマンドとして登録しても構いません)
例えば、以下のようにします。
ここでは、選択範囲を`/**/`で囲む関数funcEnclose1と、選択範囲を`""`で囲む関数funcEnclose2を定義します。

```javascript:javascript
function funcEnclose1() {
  let editor = atom.workspace.getActiveTextEditor();
  if (editor === null) {
    return;
  }

  let text = editor.getSelectedText();
  if (text !== "") {
    editor.insertText(`/*${text}*/`);
  }
}

function funcEnclose2() {
  let editor = atom.workspace.getActiveTextEditor();
  if (editor === null) {
    return;
  }

  let text = editor.getSelectedText();
  if (text !== "") {
    editor.insertText(`"${text}"`);
  }
}
```

# コマンドの登録

次に、定義した関数を呼び出すためにコマンドとして登録します。
ここで登録したコマンドはコマンドパレット(ctrl-shilf-p)を使って呼び出すことが出来るようになります。
詳しくは公式ドキュメントを見てもらうとして`atom.commands.add(target, commands)`を使って登録します。
targetには、CSS SelectorかDOM elementを指定します。
指定した要素にフォーカスが当たっているとコマンドが有効になるのですが、initファイルを使う場合、

-   `atom-text-editor`  
     テキストエディタにフォーカスが当たっているときのみコマンドが有効になる
-   `atom-workspace`  
     Atomにフォーカスが当たっているとコマンドが有効になる

のどちらかを指定すれば良いと思います。
上で挙げたencloseはテキストエディタに対する関数なので`atom-text-editor`を指定します。
commandsにはオブジェクトを渡します。
プロパティ名をコマンドの名前にし、その値を呼び出す関数にします。
あらかじめ定義された関数でなく関数式を値として渡す事も可能です。

`init.js`に以下のように記述します。
ここでは、funcEnclose1をコマンド名commandEnclose1、funcEnclose2をコマンド名commandEnclose2として登録しています。

```javascript:javascript
atom.commands.add("atom-text-editor", {
  "commandEnclose1": funcEnclose1,
  "commandEnclose2": funcEnclose2
});
```

これで関数を実行することが出来るようになりました。
実行するには、エディタ上の文字列を選択した状態でコマンドパレット(ctrl-shilf-p)を開き、commandEnclose1(commandEnclose2)を呼び出すと関数funcEnclose1(funcEnclose2)が呼び出されて選択した文字列が`/**/`(`""`)で囲まれます。

# メニューおよびコンテキストメニューへの登録

最低限実行させるためにはコマンドの登録までで良いのですが、メニューに登録してそれから実行させることも出来ます。

登録には、`atom.menu.add(items)`を使います。
itemsは、オブジェクトの配列で、それぞれのオブジェクトはlabel,submenu,commandプロパティを持つことが出来ます。
label,submenuには、表示したい文字列を指定します。
commandには、登録したコマンド名を指定します。
詳しくはドキュメントを見てもらうとして以下のように`init.js`に記述してください。
登録したら、`atom.menu.update()`でメニューを更新します。

```javascript:javascript
atom.menu.add([{
  "label": "InitScript",
  "submenu": [
    { "label": "enclose1", "command": "commandEnclose1" },
    { "label": "enclose2", "command": "commandEnclose2" },
  ],
}]);
atom.menu.update();
```

これでメニューに`InitScript`が出現します。
コマンドパレット以外に、メニューの`InitScript`->`enclose1(enclose2)`で実行できるようになります。

更にコンテキストメニューを追加したい場合は、`atom.contextMenu.add(itemsBySelector)`で登録します。
itemsBySelectorのプロパティには、やはり、

-   `atom-text-editor`
-   `atom-workspace`

のどちらかを登録すれば、事足りると思います。
登録した関数は、どちらもテキストエディタ上で実行する関数なので、以下のように`init.js`に記述してください。

```javascript:javascript
atom.contextMenu.add({
  "atom-text-editor": [
    { "label": "enclose1", "command": "commandEnclose1" },
    { "label": "enclose2", "command": "commandEnclose2" },
  ],
});
```

これで、テキストエディタにフォーカスが当たっている状態で右クリックするとenclose1( enclose2)が出現し、実行できるようになります。

# keybind
よく使うコマンドならばショートカットキーを登録しておくと便利です。
ここで作成したコマンドもショートカットキーを割り当てることができます。

まずは、
`File` -> `Keymap...`
でKeymapファイルを開きます。
ここで開かれるファイルは、`keymap.cson`です。
jsonファイルよりcsonファイルの方が便利なので、ここではそのまま使います。

`keymap.cson`では、まずはセレクタを設定します。
そして、セレクタの入れ子として操作キーと呼び出されるコマンドを登録します。
セレクタとして登録された要素に操作フォーカスが当たっている時に、登録されているキーを押すとコマンドが実行されるようになります。

セレクタには、例によってやはり、

-    `atom-text-editor`
-    `atom-workspace`

のどちらかを設定すれば良いです。

ここでは、`atom-text-editor`にフォーカスが当たっているときに、ctrl-1を押したときにcommandEnclose1が、ctrl-2を押したときにcommandEnclose2が実行されるようにしてみたいと思います。
以下のように、`keymap.cson`を記述してください。

```coffeescript:cson
"atom-text-editor":
    "ctrl-1": "commandEnclose1"
    "ctrl-2": "commandEnclose2"
```

これで作成したコマンドを、ショートカットキーで実行できるようになります。

# 最後に

自分用の関数を登録して快適なエディタライフをお送りください。
関数に引数を動的に渡す方法があればもっと便利になりそうですが、上手い方法はあるのでしょうか。
と書いていましたが自己解決して記事を書きました。
よろしければこちらもお読みください。
[Atom Editor用の取るに足らない自作Init Scriptを紹介してみる][url1]


# ソース

コピー用に全文を載せておきます。

`init.js`

```javascript:javascript
function funcEnclose1() {
  let editor = atom.workspace.getActiveTextEditor();
  if (editor === null) {
    return;
  }

  let text = editor.getSelectedText();
  if (text !== "") {
    editor.insertText(`/*${text}*/`);
  }
}

function funcEnclose2() {
  let editor = atom.workspace.getActiveTextEditor();
  if (editor === null) {
    return;
  }

  let text = editor.getSelectedText();
  if (text !== "") {
    editor.insertText(`"${text}"`);
  }
}

atom.commands.add("atom-text-editor", {
  "commandEnclose1": funcEnclose1,
  "commandEnclose2": funcEnclose2,
});

atom.menu.add([{
  "label": "InitScript",
  "submenu": [
    { "label": "enclose1", "command": "commandEnclose1" },
    { "label": "enclose2", "command": "commandEnclose2" },
  ],
}]);
atom.menu.update();

atom.contextMenu.add({
  "atom-text-editor": [
    { "label": "enclose1", "command": "commandEnclose1" },
    { "label": "enclose2", "command": "commandEnclose2" },
  ],
});
```

`keymap.cson`

```coffeescript:cson
"atom-text-editor":
    "ctrl-1": "commandEnclose1"
    "ctrl-2": "commandEnclose2"
```

[url1]:https://qiita.com/BlueSilverCat/items/a995a41f2a5d05887780