CodeMirrorでSparqlを美しく表示する


[CodeMirror](http://codemirror.net/index.html)というブラウザで動くテキストエディタのライブラリがあります。
これを使ってSparqlをシンタックスハイライトしましょう。

# 注意
Sparqlにシンタックスハイライトする方法です。
Sparqlの整形(Auto Format)方法は記載していません。

# 1st Step
## お手本
[Home](http://codemirror.net/)の

```html
<!-- Create a simple CodeMirror instance -->
<link rel="stylesheet" href="lib/codemirror.css">
<script src="lib/codemirror.js"></script>
<script>
  var editor = CodeMirror.fromTextArea(myTextarea, {
    lineNumbers: true
  });
</script>
```
を参考にしましょう。

## npmでソースコードを入手

一見、ソースコードの入手方法がわかりません。
[npmパッケージ](https://www.npmjs.com/package/codemirror)があります。
これを使います。

## ページ作成

```
npm init -y
npm i codemirror
```

```html:index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Code Mirror Sample</title>
    <link rel="stylesheet" href="node_modules/codemirror/lib/codemirror.css">
    <script src="node_modules/codemirror/lib/codemirror.js" charset="utf-8"></script>
</head>

<body>
    <textarea id="myTextarea" rows="8" cols="40"></textarea>
    <script>
        CodeMirror.fromTextArea(myTextarea, {
            lineNumbers: true
        })
    </script>
</body>

</html>
```

## 起動
素っ気ない、行番号が表示されたエディタが表示されれば成功です。

![スクリーンショット 2016-10-08 14.47.33.png](https://qiita-image-store.s3.amazonaws.com/0/15964/cc34fbb3-ca8c-bee9-96ea-0e806e92e262.png "スクリーンショット 2016-10-08 14.47.33.png")

# 2nd Step "SPARQL mode"
[SPARQLモード](http://codemirror.net/mode/sparql/)を試してみます。

## お手本
```html
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="sparql.js"></script>
<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
  <a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>

  <ul>
    <li><a href="../../index.html">Home</a>
    <li><a href="../../doc/manual.html">Manual</a>
    <li><a href="https://github.com/codemirror/codemirror">Code</a>
  </ul>
  <ul>
    <li><a href="../index.html">Language modes</a>
    <li><a class=active href="#">SPARQL</a>
  </ul>
</div>

<article>
<h2>SPARQL mode</h2>
<form><textarea id="code" name="code">
PREFIX a: &lt;http://www.w3.org/2000/10/annotation-ns#>
PREFIX dc: &lt;http://purl.org/dc/elements/1.1/>
PREFIX foaf: &lt;http://xmlns.com/foaf/0.1/>
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#>

# Comment!

SELECT ?given ?family
WHERE {
  {
    ?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .
    ?annot dc:creator ?c .
    OPTIONAL {?c foaf:givenName ?given ;
                 foaf:familyName ?family }
  } UNION {
    ?c !foaf:knows/foaf:knows? ?thing.
    ?thing rdfs
  } MINUS {
    ?thing rdfs:label "剛柔流"@jp
  }
  FILTER isBlank(?c)
}
</textarea></form>
    <script>
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
        mode: "application/sparql-query",
        matchBrackets: true
      });
    </script>

    <p><strong>MIME types defined:</strong> <code>application/sparql-query</code>.</p>

  </article>
```

## ページ作成
ポイントは

- addon/edit/matchbrackets.jsはなくても見た目は変わらない
- エディタの高さはtextareaではなく`CodeMirror`クラスに指定

です。

```html:index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Code Mirror Sample</title>
    <link rel="stylesheet" href="node_modules/codemirror/lib/codemirror.css">
    <style media="screen">
      .CodeMirror{
        height: 400px;
      }
    </style>
    <script src="node_modules/codemirror/lib/codemirror.js" charset="utf-8"></script>
    <script src="node_modules/codemirror/mode/sparql/sparql.js" charset="utf-8"></script>
</head>

<body>
    <textarea id="code" name="code">
PREFIX a: &lt;http://www.w3.org/2000/10/annotation-ns#>
PREFIX dc: &lt;http://purl.org/dc/elements/1.1/>
PREFIX foaf: &lt;http://xmlns.com/foaf/0.1/>
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#>

# Comment!

SELECT ?given ?family
WHERE {
  {
    ?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .
    ?annot dc:creator ?c .
    OPTIONAL {?c foaf:givenName ?given ;
                 foaf:familyName ?family }
  } UNION {
    ?c !foaf:knows/foaf:knows? ?thing.
    ?thing rdfs
  } MINUS {
    ?thing rdfs:label "剛柔流"@jp
  }
  FILTER isBlank(?c)
}
    </textarea>

    <script>
        var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
            mode: "application/sparql-query"
        });
    </script>

</body>

</html>
```

## 起動
色わけされたSparqlが表示されます。

![スクリーンショット 2016-10-08 16.02.49.png](https://qiita-image-store.s3.amazonaws.com/0/15964/630a83b3-5f58-bf8d-f3a8-41a65f624ca7.png "スクリーンショット 2016-10-08 16.02.49.png")


# 3rd step 編集禁止
[Configuration](http://codemirror.net/doc/manual.html#config)に`readOnly`があります。

> This disables editing of the editor content by the user. If the special value "nocursor" is given (instead of simply true), focusing of the editor is also disallowed.


CodeMirrorの初期化オプションに`readOnly: true`を追加すれば編集禁止になります。

```js
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    mode: "application/sparql-query"
    readOnly: true
});
```

# 4th Step 自動改行
改行のないSparqlを渡すと無限に長く表示されます。

![スクリーンショット 2016-10-08 16.16.58.png](https://qiita-image-store.s3.amazonaws.com/0/15964/dbdfab19-2b3d-5b70-b84b-118cedc353f9.png "スクリーンショット 2016-10-08 16.16.58.png")

アドオン[wrap/hardwrap.js](https://codemirror.net/demo/hardwrap.html)を使って改行します。

## お手本

```js
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
  mode: "markdown",
  lineNumbers: true,
  extraKeys: {
    "Ctrl-Q": function(cm) { cm.wrapParagraph(cm.getCursor(), options); }
  }
});
var wait, options = {column: 60}, changing = false;
editor.on("change", function(cm, change) {
  if (changing) return;
  clearTimeout(wait);
  wait = setTimeout(function() {
    changing = true;
    cm.wrapParagraphsInRange(change.from, CodeMirror.changeEnd(change), options);
    changing = false;
  }, 200);
});
```

## ページ作成
ポイントは

- プラグインを読み込む
- `wrapParagraph`関数を呼び出す


```html:index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Code Mirror Sample</title>
    <link rel="stylesheet" href="node_modules/codemirror/lib/codemirror.css">
    <style media="screen">
      .CodeMirror{
        height: 400px;
      }
    </style>
    <script src="node_modules/codemirror/lib/codemirror.js" charset="utf-8"></script>
    <script src="node_modules/codemirror/mode/sparql/sparql.js" charset="utf-8"></script>
    <script src="node_modules/codemirror/addon/wrap/hardwrap.js" charset="utf-8"></script>
</head>

<body>
    <textarea id="code" name="code">
SELECT ?it1 ?st1 ?p01 ?x01 ?p02 WHERE {?it1 ?st1 <http://www4.wiwiss.fu-berlin.de/diseasome/resource/diseasome/genes> . ?it1 ?p01 ?x01 . <http://www4.wiwiss.fu-berlin.de/drugbank/resource/targets/578> ?p02 ?x01 . FILTER (isIRI(?it1) && isIRI(?x01)) FILTER (?it1 != ?x01) FILTER (str(?p01) NOT IN ("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2000/01/rdf-schema#subClassOf", "http://www4.wiwiss.fu-berlin.de/diseasome/resource/diseasome/class", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugType", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugCategory", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/dosageForm")) FILTER (str(?p02) NOT IN ("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2000/01/rdf-schema#subClassOf", "http://www4.wiwiss.fu-berlin.de/diseasome/resource/diseasome/class", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugType", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugCategory", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/dosageForm")) FILTER (str(?st1) IN ("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2000/01/rdf-schema#subClassOf", "http://www4.wiwiss.fu-berlin.de/diseasome/resource/diseasome/class", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugType", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/drugCategory", "http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/dosageForm"))} LIMIT 10</textarea>

    <script>
        var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
            mode: "application/sparql-query",
            readOnly: true,
            hardwrap: true
        });

        editor.wrapParagraph()
    </script>

</body>

</html>
```

## 起動

有限の幅で色分けしたSparqlが表示できました。

![スクリーンショット 2016-10-08 16.59.21.png](https://qiita-image-store.s3.amazonaws.com/0/15964/5786eb61-5208-33ff-37bd-b80e9717ba43.png "スクリーンショット 2016-10-08 16.59.21.png")

# 課題
できることなら自動整形したいものです。

[YASQE](http://yasqe.yasgui.org/)には自動整形機能があります。
デモページでは、私の扱っているSpaqlを、思ったように整形してくれませんでした。