2013年8月21日水曜日

Sublime Text 2 用の ReVIEW プラグイン作った

ReVIEW とは「テキストマークアップ型の原稿フォーマット」であり html, pdf, epub などの形式に変換することができます。
詳しくは kmuto さんの 「書籍制作フローを変える。 「ReVIEW」という解。[PDF]」「ReVIEWによる書籍制作フローを勉強する会を開いたよ : hdk_embeddedの日記」 を見るといいと思います。

ReVIEW 自体は github で公開されています。
https://github.com/kmuto/review

上記「ReVIEWによる書籍制作フローを勉強する会を開いたよ」内で言及されている Effective Android というコミケ本の制作に関わりました。 この本自体は用意した150部がコミケ3日目開始40分でそうそうに売り切れてしまうという結果になり、現在電子書籍化に向けていろいろ動いているようです。 制作にあたり著者が20人以上と多いので、フォーマットを合わせるために ReVIEW を使って原稿を書くことになりました。

この原稿以降も別の原稿を ReVIEW で書いたり、仕様書を ReVIEW で書いたりよく利用しています。
プレインテキストなのでバージョン管理ツールで変更履歴が見やすいという点と、そこそこの校正で簡単に pdf にできるので現在の原稿がどのくらいの分量が確認しやすいというのが気に入っています。

よく利用するようになって、Syntax Highlight と入力補完がないのが辛くなってきたので Sublime Text 2 用のプラグインを作りました。


プラグインのインストール
  • 1. Package Control を入れる(Package Control が入ってない人のみ)
    Package Control Installation

  • 2. Package Control: Add Repository を選択
    Command + Shift + p(Window は Ctrl + Shift + p)で Command Palette を開き、Add Repository を選択


  • 3. リポジトリ URL を入力
    下の方の入力ボックスに https://github.com/yanzm/ReVIEW と入力して Enter


  • 4. Package Control: Install Package を選択
    Command + Shift + p(Window は Ctrl + Shift + p)で Command Palette を開き、Install Package を選択


  • 5. ReVIEW を選択


    パッケージがダウンロードされインストールされる

  • 6. Sublime Text 2 を再起動


Syntax Highlight の使い方
  • ファイルの拡張子は .re にしてください
  • [View] - [Syntax] で ReVIEW が選択されていない場合は [View] - [Syntax] - [Open all with current extension as...] で ReVIEW を選択してください
こんな感じで色がつきます。


補完の使い方
  • Ctrl + Space で補完表示
  • 途中まで入力して Tab を押すと、そこまでで前方一致する候補の中から最初のが選択される
こんな感じで補完がでます。


* @zaki50 さんの原稿をキャプチャに使わせていただきました。ありがとうございます。



2013年8月19日月曜日

Sublime Text 2 用の Syntax Definition を作る

本家のリファレンスはこちら Syntax Definitions : SUBLIME TEXT HELP


1. AAAPackageDev を Sublime Text に入れる
  • https://bitbucket.org/guillermooo/aaapackagedev/downloads から AAAPackageDev.sublime-package をダウンロードする
  • AAAPackageDev.sublime-package を Sublime Text の Installed Packages ([Preferences] - [Browse Packages...] から開くフォルダの一つ上の階層にある)に入れる
  • Sublime Text を再起動する


2. Package を作成する

作成する Syntax Definition に対応するパッケージがない場合は

[Tools] - [Packages] - [Package Development] - [New Packages...]

を選択し、パッケージ名を入力して Enter を押す



3. Syntax Definition を作成する
  • [Tools] - [Packages] - [Package Development] - [New Syntax Definition]
  • <lang_name>.JSON-tmLanguage というファイル名で Packages/User フォルダーか、対応するパッケージフォルダに保存する { "name": "ReVIEW", "scopeName": "text.review", "fileTypes": ["re"], "patterns": [ { "match": "^={1,4} ", "name": "keyword.review", "comment": "Patagraph = " }, ... { "name": "column.review", "begin": "(^={3}\\[column\\]) ", "beginCaptures": { "1": { "name": "keyword.review" } }, "end": "(^={3}\\[/column\\])", "endCaptures": { "1": { "name": "keyword.review" } }, "comment": "Column ===[column] ... ===[/column]" } ], "uuid": "5fa7fee2-7333-4924-a208-ab04d0a64748" }
  • "name" : [View] - [Syntax] に表示される名前。
  • "scopeName" : syntax definition のトップレベルスコープ。source.<lang_name> か text.<lang_name> とする。プログラミング言語の場合は source を、マークアップなどそれ以外は text を使う。
  • "fileTypes" : 拡張子のリスト。
  • "patterns" : パターンのコンテナ。パターンは JSON 用にエスケープした正規表現で記述する。
    "name" に指定した scope 文字によって色が変わる。用意されている scope は TextMate のマニュアルにある
    • comment : コメント(灰)
      • line : ラインコメント
      • block : ブロックコメント
      { "match": "#@#.*", "name": "comment.line.review", "comment": "Comment #@# " },
    • constant : 定数
      • numeric : 数字(紫)
    • entity : エンティティ、タグ名とか
      • name :
        • function : 関数名(緑)
        • tag : タグ名(赤)
    • invalid : 無効
    • keyword : キーワード(赤)
    • markup : マークアップ言語用
    • meta :
    • storage :
    • string : 文字列(黄)
    • support :
      • function : (青)
    • variable : 変数
      • parameter : パラメータとして宣言されている変数(橙)
      • language : this, super, self などの予約語(色無し)
      • other : その他(色無し)


4. .tmLanguage ファイルに変換する
  • [Tools] - [Build System] - [JSON to Property List] を選択
  • F7(または [Tools] - [Build])を押すと .JSON-tmLanguage ファイルと同じディレクトリに .tmLanguage ファイルができる
  • Sublime Text を再起動する




# 今 ReVIEW 用の Syntax Definition 作ってるからもうちょいまって!



2013年8月9日金曜日

現在のページのストロークを全消去するシール作った enchantMOON

1. 全消去シールにしたい絵を描く



2. 指で囲って Link を選択して適当なノートを選択

3. PC と接続する

/Data/MyNotebook1/[シールを描いたページのID]/[シールID]/ に以下のファイルが作成されている
  • info.json
  • manifest.json
  • hack.js
4. [シールID] フォルダに lib フォルダを作成し、/App/MOONBlock/lib/MOON.js をコピーする
  • info.json
  • manifest.json
  • hack.js
  • lib/
    • MOON.js
5. manifest.json の "linked_pages" を空配列にする { "editor":{"name":"Columbia","version":"1"}, "linked_pages":[], "access_urls":[], "script":"hack.js" } 6. hack.js を以下のコードに書き換える /** * 現在のページのストロークをすべて削除するシール * @auther yanzm */ importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.finish(); }; sticker.onattach = function() { // 削除 var page = MOON.getCurrentPage(); var backing = page.backing; var paper = MOON.getPaperJSON(backing); // ストロークを空にする paper.strokes = []; MOON.setPaperJSON(backing, JSON.stringify(paper)); // シールをはがす MOON.peel(); MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); }); 7. PC との接続を外す

8. シールを囲んで Save を押す



9. ストークを消したいページで画面を長押ししてシール台帳を開く

10. 全消去シールをタップ





3回に1回くらいの成功率です。。。なんでだろー。。。



2013年8月8日木曜日

enchant MOON の MOON.js を見てみる

めんどいので API だけ羅列します。 気になる人は MOON.js 読んでください。別にそんな長くない。
  • html5CanvasToSerializableObject(canvas)
    HTML5 の canvas オブジェクトを渡すと pixel データを文字列にしたオブジェクトが返ってくる

  • serializableObjectToHtml5Canvas(object)
    html5CanvasToSerializableObject() で作成したオブジェクトを渡すと、HTML5 の canvas オブジェクトが返ってくる

  • loadData(src, callback)
    src で指定した URL を XMLHttpRequest を使って GET アクセスし、結果の responseText を callback に渡す importJS(["lib/MOON.js"], function() { MOON.loadData(url, function(code) { eval(code); MOON.finish(); }.bind(this)); });

  • alert(message, callback)
    message を表示したアラートを出す
    callback を渡して内部で MOON.finish() を呼ばないといけないとかなんとか。。。 importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.alert("Hello MOON", function() { MOON.finish(); }); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • penPrompt(message, callback)
    手書き入力用のプロンプトがついたアラートを出す importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.penPrompt("Hello MOON", function(input) { MOON.alert(input, function() { MOON.finish(); }); }); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); }); こんなん。プロンプト上にペンで文字を書くと認識して変換してくれる。
    文字でかくて4文字しか書けんぞ。。。




  • openStickerPage(callback)
    シール台帳を開く
    (ちなみにページのどこかを長押しするとシール台帳が開くようになっている)
    callback には選択したシール画像のパスが返ってくるらしい

    どのシールを選択しても返ってくるパスが /nullimages/sticker1.png 固定でよくわからん。。。 importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.openStickerPage(function(path) { MOON.alert(path, function() { MOON.finish(); }); }); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • openNotebook(callback)
    ページ一覧を開く
    (ちなみにページでピンチアウトするとページ一覧が開くようになっている)
    callback には選択したページのIDが返ってくるらしい

    Invalid Script もなくページ選択画面になるのだが、ページを選択すると画面が真っ暗になって うんともすんともいわなくなる。。。
    こうなると再起動するしかない。。。 importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.openNotebook(function(pageId) { MOON.finish(); }); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • uploadCurrentPageToEvernote(onsuccess, onfailure)
    Evernote に現在のページをアップロードする

  • getPageThumbnail(pageId)
    指定したページIDのページのサムネイルが canvas オブジェクトとして返ってくる

  • getEditPaperThumbnail()
    現在のページ(たぶん)のサムネイルが canvas オブジェクトとして返ってくる

  • createAPIBind()
    以下の API を MOON 以下に割り当てるのに使っている





  • peel()
    そのシールをはがす

  • finish()
    MOON を終了するっぽいことだけはなんとなくわかる

  • openUrl(url)
    ブラウザで url を開く importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.openUrl("http://www.google.co.jp"); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • openPage(pageId)
    ページを開く importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.openPage("iZjSL9Ve1375584059045"); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • setPenColor(red, green, blue, alpha)
    ペンの色を変える
    red, green, blue, alpha は 0 〜 255 までの整数 importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { var red = 255; var green = 102; var blue = 95; var alpha = 255; MOON.setPenColor(red, green, blue, alpha); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); }); 背景色や描画色は rgba 合わさった値が入っている var page = MOON.getCurrentPage(); var backing = page.backing; var paper = MOON.getPaperJSON(backing); // 背景色を取得する var color = paper.color; var transparent = paper.transparent; // color には #aarrggbb を10進数に直した値がはいっている 例)-16777216 = 0xff000000, -1 = 0xffffffff

  • setPenWidth(width)
    ペンの太さ(筆圧に対する倍率)を変える importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.setPenWidth(5.0); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • getCurrentPage()
    現在のページのオブジェクトが返ってくる { backing:"DC9g1Jkj1375584059045", papers:"GOXracRB1375753891252" } backing にはストローク情報のID、papers にはシールIDが入っているもよう
    /Data/MyNotebook1/[現在のページのID]/info.json の内容と同じっぽいが、 info.json では "stickers" だったのが "papers" になってる importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { var page = MOON.getCurrentPage(); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • setCurrentPage(page?)
    よくわからないけど、現在のページを変更する?



  • getPaperJSON(pageId)
    指定したストローク情報IDに対応するストローク情報が返ってくる

    /Data/MyNotebook1/[現在のページのID]/[ストローク情報ID]/info.json の内容っぽい { version:"0.2", x:0, y:0, width:768, height:1024, scale:1.0, color:-16777216, transparent:false, strokes:[{"width":2.5,"color":-1,"type":"pen","data":[...]}, ...] } importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { var page = MOON.getCurrentPage(); var backing = page.backing; var paper = MOON.getPaperJSON(backing); var version = paper.version; var x = paper.x; var y = paper.y; var width = paper.width; var height = paper.height; var scale = paper.scale; var color = paper.color; var transparent = paper.transparent; var strokes = paper.strokes; MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • setPagerJSON(backing, paperJSON)
    ストローク情報を書き換える importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { var page = MOON.getCurrentPage(); var backing = page.backing; var paper = MOON.getPaperJSON(backing); // paper のプロパティを変更する paper.color = -6710887; // 背景色を #ff666666 にする MOON.setPaperJSON(backing, JSON.stringify(paper)); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • getImagePath(?)
    よくわからない



  • searchWeb(query)
    ブラウザを開いて検索する importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.searchWeb("enchant MOON"); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • searchStorage(filter)
    各ノートの storage.json を検索する importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { // storage.json に fav:1 が入っているノートをピックアップする // function の引数には各ノートの storage.json をオブジェクト化したものが入っている MOON.searchStorage("function matches(j){return j[\'fav\'] > 0;}"); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); }); storage.json にプロパティを追加するには localStorage オブジェクトを使う localStorage['fav'] = 1;

  • showParticle(particle?)
    showParticles() との違いがよくわからない

  • showParticles(particles)
    パーティクルを表示する
    particles は配列で x, y, vx, vy, ?, x, y, vx, vy, ?, ... のようにデータを入れる
    5番目がわからない。フレーム数?時間?距離? importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { var page = MOON.getCurrentPage(); var backing = page.backing; var paper = MOON.getPaperJSON(backing); var x = paper.width / 2; var y = paper.height / 2; var particles = []; for (var i = 0; i < 10; i++) { particles.push(x + i, y + i, 0.1, 0.1, 40); } MOON.showParticles(particles); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });

  • recognizeStrokes(?)
    よくわからない



enchantMOON Sticker オブジェクトっているの?

他のページを開くシールの hack.js は次のようになっています。 location.replace("page://JTwZfnMf1375585755864"); また、web ページを開く hack.js は次のようになっています。 location.replace("https://maps.google.co.jp/"); どうもタップすると hack.js が実行されるようです。

そこで、hack.js を次のようにしてシールをタップすると問題なくアラートがでてきます。 importJS(["lib/MOON.js"], function() { MOON.alert('Hello MOON', function() { MOON.finish(); }); });
しかし、次のようにしてシールをタップすると、ペンの太さは変わるのですが「シールの実行に失敗しました InvalidScript」と言われます。 importJS(["lib/MOON.js"], function() { MOON.setPenWidth(5.0); MOON.finish(); }); 次のように Sticker オブジェクトを使うようにすると「InvalidScript」が出なくなります。 importJS(["lib/MOON.js"], function() { var sticker = Sticker.create(); sticker.ontap = function() { MOON.setPenWidth(5.0); MOON.finish(); }; sticker.onattach = function() { MOON.finish(); }; sticker.ondetach = function() { MOON.finish(); }; sticker.register(); });


2013年8月6日火曜日

MOON.loadData() を使って外部 js のコードを実行する

ますいさんのブログ 「_development : MOONBlockのコードをネットワーク経由で実行する」 にも書いてありますが、毎回 enchant MOON を PC に接続してコードを転送するのがめんどいので MOON.loadData() と eval() を使って外部の js コードを実行させるといろいろ捗ります。

ベースのシールの作り方は「enchant MOON で Hello world」を見てください。

シールフォルダの構成は
  • info.json
  • manifest.json
  • hack.js
  • lib/MOON.js
hack.js importJS(["lib/MOON.js"], function() { MOON.loadData("PATH TO JS", function(code) { eval(code); MOON.finish(); }.bind(this)); }); とりあえず "PATH TO JS" には Dropbox の Public においた js ファイル(以下みたいな)を指定してます。便利。 MOON.alert(MOON.getCurrentPage(), function() { MOON.finish(); });

enchant MOON で Hello world

1. シールにする絵を適当にペンで描いて、指でくるっと囲む

2. 出てきた選択肢から Link を選択して適当なページをリンク先に選ぶ

3. PC と接続する

/Data/MyNotebook1/[シールを描いたページのID]/[シールID]/ に以下のファイルが作成されている
  • info.json
  • manifest.json
  • hack.js

4. [シールID] フォルダに lib フォルダを作成し、/App/MOONBlock/lib/MOON.js をコピーする

5. manifest.json の "linked_pages" を空配列にする { "editor":{"name":"Columbia","version":"1"}, "linked_pages":[], "access_urls":[], "script":"hack.js" } 6. hack.js を以下のコードに書き換える importJS(["lib/MOON.js"], function() { MOON.alert('Hello MOON', function() { MOON.finish(); }); }); 7. PC との接続を外す

8. シールをタップする

9. 以下のようになったら OK





enchant MOON データ構造メモ

ただのメモです。
  • App/
    • MOONBlock
      • lib/
        • enchant.js
        • MOON.js
        • ...
      • js/
      • ...
  • Data/
    • MyNotebook1/
      • info.json
        ページID が配列になっている JSON { "pages":[ "wtV727cH1356966334559", "PLbZcQDz1356966337101", ... "m5cv1ak51375741607892" ] }
      • [ページID(ランダムな文字列)]/
        • info.json
          backing にストローク情報ID、stickers にシールID の配列がはいった JSON {"backing":"ストローク情報ID" ,"stickers":["シールID"]}
        • storage.json
          ローカルストレージの実体ぽい {"fav":0}
        • [ストローク情報ID(ランダムな文字列)]/
          • info.json
            ストローク情報の JSON

            "data" は x, y, 筆圧, x, y, 筆圧, ... のようにデータが入ってる { "version":"0.2", "x":0, "y":0, "width":768, "height":1024, "scale":1.0, "color":-16777216, "transparent":false, "strokes":[ { "width":2.5, "color":-1, "type":"pen", "data":[221.15625,273.7857360839844,0.09349840134382248,221.7083282470703,275.952392578125,0.0446123443543911] }, ... { "width":5.0, "color":-1, "type":"pen", "data":[223.125,285.3571472167969,0.002590776886790991,223.125,287.5535888671875,0.01993499882519245,223.21875,291.21429443359375,0.09266002476215363] } ] } 白背景(invert)にすると、color 部分が変わる { "version":"0.2", "x":0, "y":0, "width":768, "height":1024, "scale":1.0, "color":-1, "transparent":false, "strokes":[ { "width":2.5, "color":-16777216, "type":"pen", "data":[90.0,270.0714416503906,0.3157637417316437,90.75] } ] } ちなみに color の値は #aarrggbb を10進数に直した値がはいっている
        • [シール(スティッカー)ID(ランダムな文字列)]/
          • info.json
            シールのストローク情報

            例)Evernote シールの info.json
            background.png を "clip" のストロークで切り取ることができるようだ { "version":"0.2", "x":509, "y":898, "width":258, "height":89, "scale":1.0, "color":0, "transparent":true, "strokes":[], "clip":{ "width":0.0, "color":-16777216, "type":"pen", "data":[242.09375,68.21429443359375, ... 0.9757569432258606] }, "image":"background.png" }
          • manifest.json
            シールのマニフェスト
            script に指定した js が実行されるようだ { "editor": {"name":"MOONBlock","version":"1"}, "linked_pages": [], "access_urls": [], "script": "hack.js" }
          • hack.js
            実行されるスクリプト
          • background.png(ないシールもある)
          • images/ (ないシールもある)
          • lib/ (ないシールもある)
            MOON.js など、hack.js で importJS() する js ファイルがおいてある


          Evernote シールでは
          - info.json
          - manifest.json
          - hack.js
          - hack.js.old ← 残すなよw
          - background.png
          - images/
          - lib/


          Web をクリップしたシールでは
          - info.json
          - manifest.json
          - hack.js
          - background.png(Web の切り抜いた部分が収まるように四角にクリップした画像)

          manifest.json { "editor":{"name":"Columbia","version":"1"}, "linked_pages":["https://maps.google.co.jp/"], "access_urls":[], "script":"hack.js" } hack.js location.replace("https://maps.google.co.jp/");

          ブロックのサンプルシールでは
          - info.json
          - manifest.json
          - hack.js
          - images/
          - libs/

          manifest.json { "version":"1", "editor":{"name":"MOONBlock","version":"1"}, "linked_pages":[], "access_urls":[], "script":"hack.js", "blocks":[ ... ], "block_images":[] }

          描いた絵を指で囲んで link を選択して他のページ遷移できるシールを作成した場合は
          - info.json
          - manifest.json
          - hack.js


          manifest.json { "editor":{"name":"Columbia","version":"1"}, "linked_pages":["JTwZfnMf1375585755864"], (JTwZfnMf1375585755864 はリンク先のページID) "access_urls":[], "script":"hack.js" }

          hack.js location.replace("page://JTwZfnMf1375585755864"); (JTwZfnMf1375585755864 はリンク先のページID)
  • DCIM/
    • 100MOON/
      • MyNotebook1_[ページID].jpg
        ページのサムネイルが格納されている
        (私の enchant MOON では?)白背景の場合になぜか背景が薄い黄緑色になる
        (私の enchant MOON では?)黒背景の線の色が白ではなく薄い黄緑色になる
  • Screenshots/
    • Screenshot_yyyy-MM-dd-hh-mm-ss.png
      スクリーンショット(ペンの上側のボタンを押すと撮れる)が格納されている
      両サイドのページの区切り線がスクショにも入っていたが、2.3.1 のマイナーアップデートで区切り線がなくなったため、スクショにも出なくなった
  • LOST.DIR