Ace.js のシンタックスハイライターを自作する(環境構築編)

[Ace.js](http://ace.c9.io/) は、Webページに簡単に埋め込むことができるテキストエディタです。様々なプログラミング言語に対して、その記述をサポートする機能(シンタックスハイライトや自動インデントなど)が用意されており、Webページ上でのプログラミング用エディタの作成に適しています。

# この記事の目的
Ace.js には、様々な言語をサポートする機能が既に用意されています。しかし、もちろんすべての言語に用意されてはおらず、サポートに含まれない言語も存在します。特に、研究目的で作られたプログラミング言語のような、マイナーな言語はサポートされていません。ただ、Ace には言語サポート機能を自作できる仕組みが用意されています。この記事では、R-WHILE というプログラミング言語に対して、シンタックスハイライト機能を作成します。

## 環境構築編
Ace の[公式ドキュメント](https://ace.c9.io/#nav=higlighter&api=document)には、言語サポート機能を作成するための方法が記述されています。ここには、シンタックスハイライト規則や、インデント規則、コード折り畳み規則をどのように定義するのか記載されていますが、定義した規則を Ace で参照できるようにするための処理については詳しく説明されていません。環境構築編では、定義した規則を Ace で参照できる形式にする方法について公式ドキュメントであまり述べられていない部分を中心にまとめ、R-WHILE のシンタックスハイライト機能を作成する準備を行います。

# 言語サポート機能を作成する環境を構築する
## 言語サポート機能に必要なもの
Aceでは、言語の設定を `setMode` で読み込みます。この時、読み込みたい言語の設定ファイル(mode-読み込みたい言語名.js)が用意されている必要があります。例えば、次の例では `mode-javascript.js` が用意されている必要があります。

```html:*.html
<script src="js/ace.js"></script>

<div id="editor" style="height: 700px; width: 500px"></div>

<script>
    var editor = ace.edit("editor");
    editor.session.setMode("ace/mode/javascript");
</script>
```
したがって、 `mode-プログラム言語名.js` を作成できるように環境を整えることが、環境構築編の目標です。以下では、R-WHILE を具体例として、`mode-rwhile.js` を作成する手順を示します。

## mode-rwhile.js の作成
### rwhile.js と rwhile_highlight_rules.js を作成する
[公式ドキュメント](https://ace.c9.io/#nav=higlighter&api=document)には新しいモードを作成するためのテンプレートが示されています。これを参考に R-WHILE のモードを次のように記述します。ここで、ファイル名が `rwhile.js` であることに注意してください。

```javascript:rwhile.js
define(function(require, exports, module) {
   "use strict";

   var oop = require("../lib/oop");
   var TextMode = require("./text").Mode;
   var Tokenizer = require("../tokenizer").Tokenizer;

   var RwhileHighlightRules = require("./rwhile_highlight_rules").RwhileHighlightRules;

   var Mode = function() {
      this.HighlightRules = RwhileHighlightRules;
   };
   oop.inherits(Mode, TextMode);

   exports.Mode = Mode;
});
```
上の `rwhile.js` では、テンプレートから、この記事では作成しない自動インデントとコード折り畳み機能に関わる部分を省いています。

`rwhile_highlight_rules.js` は R-WHILE のシンタックスハイライト規則を定義するためのファイルです。ここでは、具体的な規則はまだ定義せず、`mode-rwhile.js` 作成に必要な最小限の記述を行います。

```javascript:rwhile_highlight_rules.js
define(function(require, exports, module) {
    "use strict";
    
    var oop = require("../lib/oop");
    var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules;
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
    
    var RwhileHighlightRules = function() {
       this.$rules = {
         "start" : [
            {
                token: token,
                regex: regex, 
                next:  next  
            }
         ]
       };
    };

    oop.inherits(RwhileHighlightRules, TextHighlightRules);
    exports.RwhileHighlightRules = RwhileHighlightRules;
});
```

以上で、`mode-rwhile.js` 作成に必要な最小限の記述が完了しました。

### mode-rwhile.js を作成する
#### 1. Ace をダウンロードする
`mode-rwhile.js` の作成には Ace でのビルドが必要になります。したがって、[https://github.com/ajaxorg/ace](https://github.com/ajaxorg/ace) から、Ace をダウンロードし、Ace に必要なライブラリをインストールします。

```console:console
git clone https://github.com/ajaxorg/ace
cd ./ace
npm install
```
#### 2. rwhile.js と rwhile_highlight_rules.js を Ace にコピーする
作成した `rwhile.js` と `rwhile_highlight_rules.js` を `ace/lib/ace/mode` にコピーします。

ace/
　├ lib/
　　└ ace/
　　　└ mode/
　　　　├ rwhile.js
　　　　└ rwhile_highlight_rules.js

#### 3. Ace をビルドする
`rwhile.js` と `rwhile_highlight_rules.js` がコピーできたら、Ace をビルドします。ace ディレクトリで次のコマンドを実行します。

```console:console
node ./Makefile.dryice.js -nc
```
ビルドが完了すると、`ace/build/src-noconflict` ディレクトリに `mode-rwhile.js` が生成されます。以上で `mode-rwhile.js` の作成は完了です。

# 補足
- 開発中のR-WHILE シンタックスハイライト機能は[こちら](https://github.com/yokoyama-lab/R-WHILE_Syntax_Highlighter)から見られます。
- 上記のリポジトリでは、node モジュールを使用して、`mode-rwhile.js` の生成を自動化しています。もしよろしければ、ご覧いただけると嬉しいです。

# 次回
実際に `rwhile_highlight_rules.js` にシンタックスハイライト規則を記述し、Ace において、適切なシンタックスハイライトが行われるようにします。
→[次回](https://qiita.com/Yoshi0207/items/2bcb974ba3569559039c)

# 参考資料
- [Ace公式ドキュメント](https://ace.c9.io/)
- [Aceリポジトリ](https://github.com/ajaxorg/ace)
- [How to build a mode in ace?(stack overflow)](https://stackoverflow.com/questions/29804118/how-to-build-a-mode-in-ace)