kondoumh のブログ

- とあるソフトウェアエンジニアのめったに更新されないブログ -

ホームページを HTTPS 化

最近、Chrome や Firefox を使っているとアドレスバーの左に HTTPS 対応情報が目立つようになってきており、HTTPS 化への圧を感じます。そして、Chrome 68 からは、全ての 非 HTTPS ページに「保護されていない通信 (Not secure) 」 という警告が出るようになるそうです (現バージョン 64 でもフォーム入力画面では出ます)。

security.googleblog.com

kondoumh.com のホームページを設置しているさくらインターネットでは去年から Let's Encrypt による無料 SSL サーバー証明書が使えるようにしてくれています。

対応しなきゃと思ってましたが、年を越してはや2月下旬。ようやく本日作業しました。証明書の発行自体はさくらインターネットのコントロールパネルからポチっとやるだけ。証明書の更新もサービス側にお任せできます。http -> https のリダイレクト設定は .htaccess ファイルを手編集。後はページ内の HTTP リンク (主に YouTube や Amazon ウィジェット) を地道にHTTPS リンクに差し替えて*1完了。

kondoumh.com

ついでに独自ドメインで運用している Tumblr も HTTPS 設定しました。

reblog.kondoumh.com

はてなブログはサービス側の HTTPS 対応が完了して独自ドメインでの対応方法が分かってから考えたいと思います。

2018.6.20 追記) はてなブログも独自ドメインで HTTPS 配信に対応されましたので、移行しました。 blog.kondoumh.com

*1:画像 の URL が HTTPS になっていると Chrome の DevTools で Mixed content の警告が出ます。

iEdit 2.30 リリース

f:id:kondoumh:20160410114137p:plain

約3年!!放置しておりました。ご無沙汰してました。

今回、機能追加やバグ修正はありません。

HiDPI 環境対応

最近 HiDPI をサポートした PC やタブレットが増えて、MacBook の Retina ディスプレイさながらテキストやアイコンなどを高い画素密度で美しく表示できる環境が普及しています。残念ながら iEdit を HiDPI 環境で動かすと、ツールバーのボタンや各ビューのスケールが縮小されてとても使えない状態になってしまいます。

f:id:kondoumh:20180212120614p:plain

本格的に対応するとなると、ウィンドウ生成周りや描画周り (特にダイアグラム部分) のレガシーなコードを書き直す必要がありますが、全く気乗りしない作業です。それで放置期間が長引いてしまいました。

今回、HiDPI を無視するビルドオプションの存在を知ったのがリリースのきっかけでした。このオプションでビルドしたバイナリを実行すると OS は「こいつ HiDPI って知らずに起動してるじゃん」と気付いて、どんな高精細のディスプレイ上でも、昔ながらの SVGA 的なサイズ感 *1 に調整してくれます。HiDPI じゃない環境では従来通り起動されます。実は起動用アイコンのプロパティで互換性の設定をすれば同じようなことができるのですが、利用者の手間が増えてしまうのと、必ずしも有効になるわけではなかったので、ビルドオプションで対応することにしました*2

f:id:kondoumh:20180212120653p:plain

ツールバーは16色のまま、ダイヤグラムは GPU によるレンダリングにも対応しないため*3、古臭い感が抜けませんが、まあベースが古いので・・。しかし、Microsoft はレガシー Win32 アプリの面倒をよく見てくれて助かります*4

Windows 10 サポート

前回リリース時はまだ Windows 8 時代で Windows 10 は Insider Preview でしたが、今や Windows 7 に拮抗するシェアを獲得しています。私も会社のラップトップが Windows 7 ですが Windows 10 オンリーになる日もそう遠くなさそうです*5。今回は Windows 7 でも動作確認してるので、おそらく 8 / 8.1 でも動作するのではないかと思います 。

Windows 10 サポートでやったことは最新の Visual C++ 2017 (内部バージョン 14.1) と Windows SDK (10.0.14393.0) でビルドしたこと、バージョン判定ロジックを修正したことぐらいです。Visual Studio 2017 でインストーラもガラリと変ってしまい、環境構築やプロジェクトの移行方法がよく分からなかったことも放置期間が長引いた原因になりました。

今後

ということで、ビルドし直しただけに近いリリースですが、マイナーバージョンを1つ上げました。 今後どの程度更新するか謎ですが、

  • コードベースの大幅変更を予定しない
  • 開発環境を常に最新版に更新して保守用環境 = 日常使いの環境にしておく

という状態になったので気楽に更新できる気がしています。

*1:96DPI のディスプレイに表示した感じです。

*2:開発機が MacBook なので VMware Fusion 上の 仮想マシン (Windows 10 Fall Creators Update) で HiDPI を有効にして確認していますが、このバージョンではスケーリングの描画がかなり改善されたみたいなので、初期バージョンの Windows 10 では表示のされ方が異なるかもしれません。

*3:GPU を活かすべく Direct 2D も試してましたがそのコードも revert しました。

*4:なんとストアに出すためのオプションまであります。Windows は元来下位互換性を重視するプラットフォームですけどね。ディベロッパーが UWP アプリをガンガン開発してくれないからかもしれませんが。

*5:Update による違いがどのぐらい顕著になっていくのかは今のところ謎です。Windows 10 も古いビルドはサポート終了になっていたりします。

個人開発用 VPS を捨て Cloud IDE に移行する

2年近く VPS を維持してきました (Ubuntu 16.04 LTS 32bit 2GB RAM : 980yen/month)。

  1. Node.js で CLI ツール作る
  2. Web API や Web UI のお試しコードを書く
  3. 未知の言語のコンパイラや REPL を使ってみる

などの用途に。

昨年末 Codenvy を触ってみて、もう VPS 常時起動なんかやめて必要時に Cloud IDE 使えばいいんじゃないかと思い始めました。

blog.kondoumh.com

未知の言語用環境構築は依存ライブラリのバージョンとかでハマることも多く自由度の高い VPS の方が重宝します*1が、Node.js や Web 開発は標準的な構成で使うためクラウドで提供されている環境で十分な気がします。

有象無象の Cloud IDE から今回は、新興の Codenvy、老舗の Codeanywhere、昨年登場した AWS Cloud9 の3つを無料枠の範囲で試してみました。

Node.js の CLI ツールや Web API の簡単なクライアント画面のコードを Bitbucket のリポジトリに置いて、

  • 環境構築
  • ソースコードの取得
  • ソースコードの修正
  • 実行確認
  • ソースコードのコミット

という小さな開発プロセスを回してみました。

結果表を先に示します。以下の比較はあくまで無料の範囲内 (AWS 以外) ということにご注意ください。

Codenvy Codeanywhere AWS Cloud9
ターミナル
VCS 連携
コンテナ Docker OpenVZ EC2
コンテナ : Git リポジトリ(※1) 1 : 1 n 1 : 1 n 1 : n
PaaS 連携 Heroku DigitalOcean AWS
プロジェクトテンプレート(※2) ×
ライブラリ・ツールの追加
パッケージ管理システム APT APT Yum
独立タブによるプレビュー
インスタンスの休止 10分 ? 任意
作業フォルダの維持 ×
iOS / Android アプリ × ×
iPad での作業

(※1 追記) 執筆時点では、1:1 と思っていましたが、terminal から リポジトリを追加できますので訂正します。

(※2 追記) 執筆時点では、Codeanywhere にテンプレートがないと勘違いしていました。訂正します。

なお コードエディタ の詳細な機能比較はやっておらず、ファーストインプレッションのみです。

Codenvy

codenvy.io

Java / C++ / C# / Python / PHP / Node.js などのプラットフォームを選択してプロジェクトを構築できます。Node.js のテンプレートを選んでスタートしました。

f:id:kondoumh:20180205223919p:plain

ターミナル

Docker コンテナに ssh してターミナルが利用できます。コンソールで日本語も表示 OK です。

BitBucket 連携

git clone は Bitbucket の OAuth 認証で行けました。コンテナには docker が使われており、git のリポジトリ単位でコンテナがデプロイされます。

/projects 配下に一つだけ git リポジトリが取得されている状態になります。後から git clone で別のリポジトリを clone して開発することも可能です。

git config で user.name や user.mail を設定していてもなぜか git commit 時にエラーになってしまいます。

git config --global -l してもちゃんと設定されてるのに?? と思って、Profile -> Preferences を見ると Git -> Committer の設定画面で Name: と Email: を設定する必要がありました。ターミナルで .gitconfig 設定してもダメみたいです。

ツール・ライブラリのインストール

Node.js / npm はデフォルトで導入されています。 sudo apt-get install xxx で パッケージをインストールできました(パスワード不要)。Debian 系のようです。

コードエディタ

Eclipse Che でモダンで高機能な感じです。

実行確認

タスクランナーには Gulp を使っていますが、Node.js 環境だからか普通に実行できました。

VPS では gulp-webserver で HTML や JavaScript のアセットの更新を Watch して LiveReload してました。localhost ではなく 0.0.0.0 などのアドレスで起動するという方法でローカルのブラウザから確認していました。Docker のコンテナは 10.xx.xx.xx のようなローカル IP アドレスしか見えないため、この方法は使えません。

Codenvy の IDE では、HTML ファイルをプレビューする機能があるのでそれを使うことは可能です。ブラウザの独立したタブとして起動するので、DevTools で JavaScript のデバッグをすることもできます。LiveReload のような手放し感がないので今ひとつですが。

インスタンスの休止

無料枠だと10分でタイムアウトするので、Web で調べ物をしているうちにストップしていたりします。インストールしたツール類は残っていますが、node_modules とか作業ディレクトリは毎回クリーンされてしまうので、毎回 npm install が必要です。コードベースが大きいとツラいですね。もしかしたらオプションがあるのかもしれませんが。

iPad での作業

iPad の Chrome / Safari でも Codenvy はそこそこ動きますが、ターミナルでコマンドヒストリが呼び出せないのと、ソフトウェアキーボードでは Ctrl キーが打てないのがツラい感じでした。物理キーボードでも Ctrl キーやカーソルキーを認識しません。コマンドをがしがし打てないですが、なんとかなるレベルではあります。

その他

Heroku 連携機能があって、ブラウザだけで開発とデプロイが可能です。

Codeanywhere

codeanywhere.com

老舗と言っていい Cloud IDE で、iPad / Android のアプリまで提供されているのがすごいです。Codenvy のようなターゲットプラットフォーム毎のテンプレートのようなものはありません。 ちゃんとありました。 f:id:kondoumh:20180205223945p:plain

ターミナル

普通に使えますが、日本語は文字化けしました。あと、プロジェクトのアイコンを右クリックして出現するスペシャルなコンテキストメニューからしか起動できないため、iPad では起動できません(これが一番痛い)

BitBucket 連携

Codenvy と同様、コンテナに一つの Git リポジトリが展開されます。Git の環境は git コマンドで通常通り設定可能です。複数のリポジトリを clone して開発することも可能です。

ツール・ライブラリのインストール

sudo apt-get で パスワードなしでインストールできました。

コードエディタ

Eclipse Che より機能は劣る感じがしますが、動作が軽く Horizontal / Vertical に画面を分割できるし、中々使いやすい感じです。VS Code や Atom のように JSON を編集して設定します。

実行確認

gulp タスクの実行、ページのプレビューなどは Codenvy と同様に可能です。

インスタンスの休止

一定時間でリサイクルされますが、node_modules や作業フォルダはそのまま残っていますので、毎回、npm install とかする必要はありません。コンテナのロゴなどは特に表示されませんが、公式サイトによれば、OpenVZ が使われているようです。

iPad での作業

iPad の Chrome / Safari でもほぼデスクトップと同様に使えますが、iOS では、上記のようにターミナルの起動ができません。プレビューもスペシャルなコンテキストメニューで行うのですが、iPad ではファイル単位で呼び出せません。

専用アプリを使うとターミナルやプレビューは可能ですが、フルスクリーン画面しかなく IDE のような使い勝手ではありません。Split View にも未対応で、iPad の機能を活かしきれていない感じです。アプリで物理キーボード使っても Ctrl キーとか効きません。この辺はもう少し頑張ってほしいところです。ていうか、アプリ頑張るのではなく Web IDE でスペシャルなコンテキストメニューじゃなく通常のメニューから使えるようにしてくれるだけでいいのですが・・・。

現状、アプリを使わざるを得ず、IDE のメリットが享受できない感じがあります。

その他

DigitalOcean と連携できる模様です。

IDE だけなら Codenvy の方が使いやすい感じですが、作業フォルダが残るところとか、モバイルアプリがあったりと普段使いなら Codeanywhere の方が現実的な気がします。

AWS Cloud9

aws.amazon.com

AWS に買収された Cloud IDE。サーバーレスアーキテクチャな Lambda の開発プラットフォームとして昨年末の AWS re:invent で発表されました。オリジナルの Cloud9 もありますが、Lambda にも興味ありということで、この際 AWS アカウントを作成し IMA コンソールでユーザを追加。

Codenvy 同様プラットフォームごとのテンプレートが用意されています。

f:id:kondoumh:20180205224151p:plain

ターミナル

普通に使えます。

BitBucket 連携

Codenvy / Codeanywhere は Git リポジトリ単位のプロジェクトでしたが、Cloud9 のコンテナは EC2 そのものです。ですので、一つのコンテナに複数のプロジェクトを構築できます。

ツール・ライブラリのインストール

node と npm は最初から入ってました。

sudo apt-get でパッケージをインストールしようとしたらエラーが出て yum 使えと popup が出ました。Redhat 系のようですね。 sudo yum install xx で パスワードなしで導入できました。

コードエディタ

Ace Editor が使われており、モダンテキストエディタそのものです。Sublime Mode などのプリセットが用意されています。

実行確認

gulp タスクは当然実行可能。プレビューは IDE 内のタブとして起動します。そのままでは DevTools でデバッグできませんが、アドレスバーの横に Pop Out Into New Window というツールチップの出るボタンがあり、クリックすると新しいタブとして開くことができます。

インスタンスの休止

課金怖いので30分で休止するようにしています。作業フォルダや node_modules がリサイクルされることはありません。

iPad での作業

ターミナルでの Ctrl キーはやはり入力できませんでした。コマンドヒストリは使えます。なんとか作業はできるレベルだと思います。

その他

EC2 の VPS を WebUI で使える感じです。Lambda の開発も試してみたいところです。 ちなみに、Cloud9 自体は GWT*2 で作られているようです。

まとめ

ソースコードが、GitHub や BitBucket にあればすぐに取得して開発・実行環境を構築できる Cloud IDE。それぞれ、テンプレートからプロジェクトを生成できたり、PaaS と連携できたり、iOS / Android 端末でも使えたり・・。当然ローカルの開発環境の方が生産性は格段にいいですが環境構築が簡単で iPad とか Chromebook さえあればどこでも開発できるユビキタスな感じは Cloud IDE の魅力ですね。 VPS は解約しました。iPad からも Prompt 2 とかを削除。 普段使いで PC では Codenvy、iPad では Codeanywhere 、AWS の機能を使いたい時は Cloud9 のように使い分けようかと思います。

*1:Docker 使えばいい気がします。

*2:Google Web Toolkit

VS Code の統合ターミナルで Tig が標準装備された Git for Windows を使う

タイトル通りです。

以前、VS Code の統合ターミナルで BoW(Bash on Ubuntu on Windows) を指定して macOS に近づいた! と書いてました。

blog.kondoumh.com

macOS や Linux では Git リポジトリの Text-mode interface である Tig を愛用しています。

github.com

BoW の時は Ubuntu に導入した Tig がそのまま統合ターミナルで動いたので喜んでたのですが、会社マシンはいまだに Windows 7 で BoW は使えませんし、自宅 MacBook の仮想マシンの Windows 10 にはわざわざ BoW とか入れてません*1。Gygwin とか今更入れたくないしなーと時々思い出したように Windows 版のバイナリ探してました。GitHub にも Windows build ないの〜? という Issue が立ってました。

github.com

先日久々にチェックしたら去年の9月に作者の人が「Tig が Git for Windows に同梱されたよ!」ってリリースノートのリンクを貼ってました。

Release Git for Windows 2.14.2 · git-for-windows/git · GitHub

Git for Windows は使ってますが、導入日付を見ると 2016年。そこで最新版をインストールしたら、ちゃんと Tig が使えました。

Git for Windows は MSYS2 を統合しています。MSYS2 は MinGW を補完する MSYS の後継プロジェクト・・とまあ Windows に Unix のシェルとツールチェインを提供する OSS で Cygwin の遠い親戚です。Cygwin よりも Windows との親和性を考慮して開発されています。

MSYS2 homepage

なので Git for Windows のシェル環境を VS Code の統合ターミナルで使えばいいじゃないのと思って設定してみました。

"http://terminal.integrated.shell.windows ": "C:\\Program Files\\Git\\bin\\bash.exe"

普通に使えて統合ターミナル内で Tig も動きました。MSYS2 のシェルのオーバーヘッドがあるためか、ターミナルの起動はややもたつきますが、起動してしまえば問題ありません。

f:id:kondoumh:20180125121712p:plain

MSYS2 ベースなので、Windows のシェルとの相互運用がよくできています。BoW だと Linux に Windows のファイルシステムがマウントされているので、/mnt/c/Users/kondoumh のようなパスになるのですが、Git for Windows だと /c/Users/kondoumh とマウントを意識させない感じのパスが使えます。Windows 標準の cmd.exe にコマンド実行を委譲してくれるので start . でカレントフォルダでエクスプローラを起動してくれますし、notepad でメモ帳が起動します。

Git と Node.js のエコシステムが普通に使えるので、VS Code のシェルとしては非常に馴染みます。Windows 10 を使っていても Linux のネイティブ開発でない限り、BoW よりこちらの方がよさそうです。

ということで、VS Code + Git for Windows (・∀・)イイ!! という話でした。

*1:統合ターミナルで BoW の記事投稿時は BootCamp で Windows 10 を使ってました

VS Code の ChangeLog 用 Extension を作成する

メモ取りを VS Code に移行すると決めたので ChangeLog フォーマット用の環境を整える必要が出てきました。

blog.kondoumh.com

欲しいのは Emacs の組み込み changelog-mode (シンタックスハイライトと項目追加コマンド) 程度の機能です。

Syntax Hilighting

シンタックスハイライトについては、元祖モダンテキストエディタである TextMate で使われていたハイライト定義が後発の Atom や VS Code でもサポートされています。

OrgMode のハイライト定義を頑張って作ってる人はいましたが、ChangeLog 形式のファイルを公開している人は見つかりませんでした。GitHub では ChangeLog が Markdown で書かれている場合が多く必要性が低いと推測されます。そして OSS には ChangeLog がつきものなのでググラビリティも低いです。

ということで、log ファイルのコードハイライトサンプルを参考に作りました。

github.com

後述の VS Code 拡張の開発環境を整えると、Yeomen でジェネレートできる*1のですが、今回は上記のサンプルを編集しました。

changelog.tmLanguage.json: ハイライト定義ファイルの本体です。

{
    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
    "name": "changelog",
    "patterns": [{
            "include": "#tag"
        },
        {
            "include": "#headline"
        },
        {
            "include": "#list"
        }
    ],
    "repository": {
        "tag": {
            "patterns": [{
                "match": "^\\t(\\*)\\s([^:]+)(:).*",
                "captures": {
                    "1": {
                        "name": "constant.regexp.changelog"
                    },
                    "2": {
                        "name": "markup.changed.changelog"
                    },
                    "3": {
                        "name": "constant.regexp.changelog"
                    }
                }
            }]
        },
        "headline": {
            "patterns": [{
                "match": "^([0-9]{4}-[0-9]{2}-[0-9]{2})\\s+([日月火水木金土])\\s+<([^@]+@[^@]+)>$",
                "captures": {
                    "1": {
                        "name": "markup.deleted.changelog"
                    },
                    "2": {
                        "name": "comment.changelog"
                    },
                    "3": {
                        "name": "entity.name.tag.css.changelog"
                    }
                }
            }]
        },
        "list": {
            "patterns":[{
                "match": "^\\t(\\-)\\s.*$",
                "captures": {
                    "1": {
                        "name": "constant.numeric.changelog"
                    }
                }
            }]
        }
    },
    "scopeName": "source.changelog"
}

日付 + メールアドレスの正規表現を headline、各項目を tag、項目内のリスト要素を list という名前でそれぞれタグ付けして reposiotry に定義し patterns から include しています。

各パターンにマッチしたグループごとに name 属性で色指定をしています。name 属性は TextMate から引き継がれている配色指定のキーになっています。

VS Code の Dark theme ファイル (macOS では下記のパスに格納されています) を VS Code で閲覧しながら適当に指定しました。

/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/theme-defaults/themes/dark_vs.json

ChangeLog は単純な構造なので定義ファイルもコンパクトです。

package.json: ハイライト定義に関するパッケージ情報を定義します。displayName などの属性を設定します。

{
    "name": "changelog-highlight",
    "displayName": "changelog-highlight",
    "description": "A simple extension for changelog syntax highlighting.",
    "version": "0.0.1",
    "publisher": "kondoumh",
    "engines": {
        "vscode": "^1.19.0"
    },
    "categories": [
        "Languages"
    ],
    "contributes": {
        "languages": [{
            "id": "changelog",
            "aliases": ["changelog", "changelog"],
            "extensions": ["ChangeLog"],
            "configuration": "./language-configuration.json"
        }],
        "grammars": [{
            "language": "changelog",
            "scopeName": "source.changelog",
            "path": "./syntaxes/changelog.tmLanguage.json"
        }]
    }
}

language-configuration.json: プログラミング言語固有の設定情報を書きます。ChangeLog は言語というほどのものではありませんが、Emacs の autopair.el のような 自動開閉する bracket の指定があるのでそのまま使うことにしました。

{
    "comments": {
    },
    "brackets": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"]
    ],
    "autoClosingPairs": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"],
        ["\"", "\""],
        ["'", "'"]
    ],
    "surroundingPairs": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"],
        ["\"", "\""],
        ["'", "'"]
    ]
}

launch.json: VS Code 起動時に読み込む設定をします。

// A launch configuration that launches the extension inside a new window
{
    "version": "0.1.0",
    "configurations": [
        {
            "name": "Launch Extension",
            "type": "extensionHost",
            "request": "launch",
            "runtimeExecutable": "${execPath}",
            "args": ["--extensionDevelopmentPath=${workspaceRoot}" ]
        }
    ]
}

以上のファイルを下記構造で ~/.vscode/extensions 配下に置くと VS Code 起動時に読み込んでくれます。

~/.vscode/extensions/changelog-highlight
│  language-configuration.json
│  package.json
│
├─.vscode
│      launch.json
│
└─syntaxes
        changelog.tmLanguage.json

Insert headline Extension

VS Code では日付挿入のような簡単な処理でも Emacs や Vim のように設定ファイルに関数を書いて呼びだすようなことはできず、Extension を作ってインストールするしかないようです。

なんかめんどくさい印象ですが、↓ のチュートリアルに従って Extension のプロジェクトを生成すると案外あっさりできました。拡張を書く障壁を低くするよう頑張ってくれてるみたいです。

code.visualstudio.com

拡張機能は、TypeScript / JavaScript で作成できます*2

以下のように Yeoman と VS Code の ジェネレータを npm で導入し、ジェネレートコマンドを実行すると、コマンドラインで対話的に雛形が作成できます。

$ npm install -g yo generator-code
$ yo code

今回は JavaScript を選択しました。Git リポジトリの初期化も選択すればやってくれます。生成されたプロジェクトを読み込んで、F5 キーを押すかデバッグボタンをクリックすると Extension を読み込んだ状態の VS Code のプロセスが別に起動され、デバッグできます。

package.json: ジェネレート時に指定した displayName などが設定されます。contributes.commands の配列が Extension 使用時にコマンドパレットに表示される コマンド群になります。

{
    "name": "insert-changelog-headline",
    "displayName": "insert-changelog-headline",
    "description": "extension to insert changelog headline",
    "version": "0.0.1",
    "publisher": "kondoumh",
    "engines": {
        "vscode": "^1.19.0"
    },
    "categories": [
        "Other"
    ],
    "activationEvents": [
        "onCommand:extension.insertHeadline"
    ],
    "main": "./extension",
    "contributes": {
        "commands": [{
            "command": "extension.insertHeadline",
            "title": "Insert ChangeLog Headline"
        }]
    },
    "scripts": {
        "postinstall": "node ./node_modules/vscode/bin/install",
        "test": "node ./node_modules/vscode/bin/test"
    },
    "devDependencies": {
        "typescript": "^2.6.1",
        "vscode": "^1.1.6",
        "eslint": "^4.6.1",
        "@types/node": "^7.0.43",
        "@types/mocha": "^2.2.42"
    }
}

extension.js で拡張機能を実装します。ジェネレータではエディタ内で選択されたテキストの文字数をカウントしてポップアップするコードが生成されています。フォーマットした日付とメールアドレスをカーソル位置に挿入するコードを追加しました。

// vscode モジュールを拡張用 API を利用するためにインポート。
const vscode = require('vscode');

// 日付フォーマットのための関数。
function getFormatedDate(date, format) {
    format = format.replace(/YYYY/g, date.getFullYear());
    format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
    format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
    format = format.replace(/WW/g, ["日", "月", "火", "水", "木", "金", "土"][date.getDay()]);
    return format;
}

// 拡張が activate されるときに実行される関数。
function activate(context) {

    // 拡張が activate される時に出力する診断情報を出力。
    console.log('Congratulations, your extension "insert-changelog-headline" is now active!');

    // 拡張機能の本体を実装して登録する。package.json に設定した commandId にマッチする commandId を指定する必要がある。
    let disposable = vscode.commands.registerCommand('extension.insertHeadline', function() {

        var editor = vscode.window.activeTextEditor;
        if (!editor) {
            return;
        }
        var headline = getFormatedDate(new Date(), 'YYYY-MM-DD WW') + '  <kondoh@local>'
        var selection = editor.selection;

        editor.edit((editorEdit) => {
            editorEdit.replace(selection, '');
            editorEdit.insert(selection.active, headline);
        });
    });

    context.subscriptions.push(disposable);
}
exports.activate = activate;

// 拡張が deactivate される時に実行される関数。
function deactivate() {}
exports.deactivate = deactivate;

デバッグが完了しコードが完成したらプロジェクトフォルダを .vscode 配下にコピーし VS Code を再起動すると extension が読み込まれた状態になります。 コマンドパレットから呼び出して、headline を挿入できるようになります。

f:id:kondoumh:20180112065116p:plain

もちろんパッケージを作って Marketplace で公開することも可能です。

marketplace.visualstudio.com

ということで、VS Code で快適に ChangeLog メモを書けるようになりました。

VS Code の Extension は Node.js のエコシステムで開発できるので汎用的なスキルセットが使えて色々高度な自動化ができそうです。

あと Emacs Friendly Keymap を入れるとかなり Emacs です。

marketplace.visualstudio.com

*1:テンプレートに Coloer Theme が用意されています。

*2:ATOM エディタは CoffeeScript でしたね。

ChangeLog メモの移行先を考える

メモ環境をモダン化したい

Trello に移行してみて日常に定着するツールの必要条件としてデスクトップ・モバイルともに使いやすい UI が提供されることが重要だと実感しました。

blog.kondoumh.com

OrgMode は Emacs 使える環境じゃないとダメなので使う頻度が下がってます。

blog.kondoumh.com

日常のメモについては10年以上 ChangeLog メモを Vim や Emacs で書いていて、最近だと Dropbox に Sync しスマホや iPad でもテキストエディタで編集するというスタイルです。

blog.kondoumh.com

ChangeLog メモについては ↓ などをご参照ください。

脱 Emacs もしたいですし、モバイルの UX も向上してほしいです。

移行候補としての Markdown ツール

Markdown エディタはデスクトップでもモバイルでも昔から結構な数ありますが、最近 Electron や React Native (RN) など Web 由来の技術で開発されたクロスプラットフォーム & マルチスクリーンなツールが増えてきました。Electron は Web の洗練された UI とローカルストレージへのデータアクセス機能を提供できます。RN は iOS や Android のコンポーネントを抽象化しているので、各プラットフォームにそれなりの UI を提供可能です。

正月休みにいくつかのツールを試してみました。

  • Joplin
  • Boostnote
  • Quiver

の3つです。

対応プラットフォーム、データフォーマットなど並べてみました。フィーチャーとしてストレージサービス対応、タグ付けなどは、ほぼすべてのツールで利用可能でした。デスクトップ版では執筆に集中するための Zen mode 的な機能もだいたいサポートされてます*1

クロスプラットフォームなコードエディタの最右翼 Visual Studio Code も比較対象としました。VS Code ならではのフィーチャーとしては IntelliSense による入力アシスト、Extension による機能拡張が挙げられます。

Joplin Boostnote Quiver VS Code
macOS
Windows -
Linux -
iOS -
Android - -
Format Plain Text CSON Binary Plain Text
Markdown Preview
Tagging -
ToDo List - -
Zen mode
Storage Service -
Syntax Hilighting
Input Assistance - - -
Extension - - -

以下、個別に見ていきます。

Joplin

Joplin - an open source note taking and to-do application with synchronisation capabilities

個人の OSS プロジェクトのようです。各プラットフォームを網羅しています。

ToDo 用のメモを追加できて進捗を管理できます。ToDo はメモ単位であり、メモ内に ToDo リストは持てません。

Evernote のデータをインポート可能です*2

日本語のテキスト編集にやや難があります。デスクトップもモバイルもかなり荒削りな印象。開発が進めば化けるかもしれません。

Boostnote

boostnote.io

国産の OSS らしいです。デスクトップの UI は結構頑張っている印象です。

メモ内で ToDo リストを管理できます。ToDo リストは OrgMode 形式 (リスト記法と square brackets の組み合わせ - [X]) です。プレビュー側ではチェックボックスとして表示され、チェックをオン・オフすると編集側も同期して更新される双方向バインディングです。メモ内の ToDo 総数と進捗が把握できます。この UI は Trello そっくりです。

Dropbox とのシンクロ方法は以下にありますが、先にデスクトップ版でファイルシステムとして登録しておき、モバイルアプリでシンクロするという手順が必要です。

medium.com

モバイルアプリの編集画面は簡素で保存しないとプレビューできません。RN で実装されています*3。モバイルアプリは新規メモ追加時にアプリがクラッシュするという現象が頻発していました。

ファイル形式としては、CSON *4 形式で Markdown データを内包しています。ファイル名がハッシュ値から機械的に生成されるため、ファイルが多くなってくると他ツールとの相互運用は難しいでしょう。

Quiver

happenapps.com

洗練されたデザインで、現状プロダクトとしての水準は (VS Code を除いて) 一番高い印象です。App Store の有料アプリですが、Free Trial 版が利用できます。

デスクトップは macOS オンリー。モバイルは iOS 版がありますが、編集機能はなく参照オンリーです。

ファイルが独自のバイナリ形式なので、他ツールへの乗換が面倒そうです。Apple 製品だけで生きている人にはよいかもです *5

コードのシンタックスハイライトは、Preview だけでなく 編集画面でも有効になります。

Markdown のシンタックスハイライトは若干バグっています。macOS で時々日本語入力ができなくなるなどの挙動が気になりました。

ツール評価結果

Markdown ツールのデスクトップ版は Quick / Boostnote がよさそうでした。ただ、いずれもモバイルアプリが発展途上な感じで移行がためらわれます。

タグ付け機能もローカルに複数ファイルのメモを溜め込む使い方をしていないので無くても困りません。

ToDo リストも Trello 使ってるので移行のための動機づけにはなりません。

VS Code は JavaScript 書くのに使っていて Markdown エディタとしても並のツールを凌駕しています。もはや ChangeLog のためだけに Emacs を起動しておくのもなんだし・・

結局 Markdown ツールを採用するのではなく常用エディタを Emacs から VS Code に移行することにしました。

Markdown への移行?

Markdown サポートツールが大半なので日常のメモフォーマットとして移行できないか検討しましたが ChangeLog に長年慣れた身には移行が厳しそうでした。

blog.kondoumh.com

Markdown はしっかりした構造の文書を書くためのフォーマットという意識があります。

タイトル
=============
# 見出し1
## 見出し1-1
本文
- 箇条書き1
- 箇条書き2

ChangeLog はソフトウェアアップデート情報を記述するための形式で、日付と更新者、変更内容を簡潔に書くのに適しています*6

ChangeLog 形式:

2018-01-11  Thu. <kondoumh@local>

    * 機能追加1:かくかくしかじか
    - 箇条書きも OK
    * バグ修正1:云々

ChangeLog メモは時系列的にトピックをラベル付けして箇条書きで追記していくスタイルで構造を意識してません。

10年分ぐらいのメモがこの形式で溜まっていて、データ抽出のスクリプト*7などの資産もあり、移行にはそれなりのコストがかかります*8

以上から今回はフォーマット移行しないことにしました。

CLI 命なら

今回検討対象にしていませんが mattn さんの memo コマンドというのがあります。

github.com

設定で editor を指定可能なので Vim じゃなくても使えます。VS Code と統合ターミナルで使うと快適そうです。

qiita.com

サービス専用ツール

Qiita の Kobit やはてなブログアプリなども Markdown ベースのツールですが、各サービスで Markdown を独自拡張していて汎用 Markdown ツールでは publish のイメージがわかりづらいため、専用ツールを利用するメリットはあります*9

ちなみに Kobito はシャットダウンしてしまいました。OSS として残っていますがメンテナンスされていない模様*10

Kobito for Mac / Windowsの提供及びユーザーサポートを終了します - Qiita Blog

まとめ

結局 VS Code で ChangeLog メモという結論になりました。VS Code はモバイル版の提供はありませんが、モバイルでも完成度の高いコードエディタはあるのでデータの共有は簡単。活発に開発されているユーザベースの大きいメジャー OSS であるという点も大きいです。

ChangeLog 形式サポートは何とかする必要がありますが、これについては別エントリーにしたいと思います。

追記: ChangeLog 用 Extension を書くエントリー書きました。

blog.kondoumh.com

*1:メモ取りに Zen mode が必要かという話はさておいて。

*2:Evernote は使ってないので移行先としての評価はしてません。

*3:そもそも RN の事例として知りました。

*4:CoffeeScript 版 JSON

*5:デスクトップ版はおそらくネイティブアプリでしょう

*6:日付の後にメールアドレスが入る謎仕様はこのためです

*7:正規表現モリモリです。

*8:Markdown Parser 使えばいいのでしょうが yak shaving です。

*9:はてなブログ用のアプリはあまり進化しないので、PC / iPad では Web UI を直接使った方が捗りますが。

*10:macOS 版はネイティブアプリでしたが、Windows では Electron 版が提供されてました。OSS 版は Electron 版です。

Tumblr で自分の全投稿の reblog / like 数を把握する

Web で面白そうな記事を見つけた場合、読むのに時間かかりそうなのは Pocket に保存しますが、すぐ読めそうなのはざっと読んで記事内の Tweet アイコンから Twitter に流すことが増えています。

昔は Twitter よりも Tumblr を好んで使っていたので記事内のハイライト的なパラグラフを選んで quote して Tumblr に放流してました。最近は quote の頻度は下がっており、たまに Dashboard を見に行ってポツポツと5, 6個 reblog して閉じるということが多いです*1

reblog.kondoumh.com

Tumblr に quote を放流してると、たまに reblog されまくることがあります。フォロワーの多い人に reblog され、さらに quote over100notes jp などハブアカウントに捕捉されると数が伸びます。reblog にしろ quote にしろ、オリジナルの記事を書いたわけではないので twitter の retweet とは全然別物ですが、自分が放った quote に反応があるとそれはそれで嬉しかったりします。ただ、自分のアーカイブを遡っても、notes(reblog や like) の数はあまり把握できないため、過去にどんな投稿の notes が多かったか振り返ることは簡単にできません。

以前、ストック情報サイトを tumblr のセカンドブログとして構築した時に、Tumblr API をちょっと触ってました。

blog.kondoumh.com

www.tumblr.com

ドキュメントを眺めていると notes_count など反応数も取れそうなので、HTML + JavaScript の簡易な環境でデータ取得を試してみました。確認したのは、Chrome 63.0.3239.132 です。

あらかじめ以下で API Key を取得しておきます。

https://www.tumblr.com/oauth/apps

API の URL、対象の Blog の識別子(ドメイン)、API Key をリクエスト URL 構築用に宣言します。

baseurl = "http://api.tumblr.com/v2/blog/";
domain = "your.tumblr.identifer"
api_key = "yourapikey";

投稿数を取得するには、info メソッドを利用します。

https://api.tumblr.com/v2/blog/your.tumblr.identifer/info

Blog の識別子をパスパラメータ、API Key をクエリパラメータとして指定します。 response を JSON 形式で取得すると、キー 'blog' で取得できるオブジェクトから以下のような情報が得られます。

フィールド 説明
title Blog のタイトル
posts 投稿数
name Blog の短縮名
updated 最近の投稿日時
: :

'posts' フィールドに Blog 投稿数が格納されています。

fetch API で投稿数を取得する例です。

async function getPostCount() {
    var count;
    await fetch(`${baseurl}${domain}/info?api_key=${api_key}`).then(response => response.json()).then(json => {
        count = json['response']['blog']['posts'];
    });
    return parseInt(count);
}

投稿に関する情報は、posts メソッドを使用して取得します。

https://api.tumblr.com/v2/blog/your.tumblr.identifer/posts

パスパラメータに Blog 識別子と投稿タイプ (type : text / photo / quote / link ..etc.) を指定します (投稿タイプは省略可能)。クエリパラメータとして API Key の他に reblog_infonotes_info という bool 値を指定する必要があります。一度に取得できる投稿情報は20件なので、取得開始位置を表すクエリパラメータ offset を指定して繰り返し取得します。投稿は投稿日時の降順で取得できます。

クエリパラメータ 説明
reblog_info reblog 情報を取得するか指定
notes_info notes(reblog や like) 情報を取得するか指定
offset 投稿の取得開始位置

reblog_info を指定すると reblog 情報として、reblogged_root_name が取れます。これが実はオリジナルの投稿者 (blog 短縮名)で、この値が取得できない場合、それは自分の投稿ということになります*2notes_info を指定すると投稿に対する反応 (reblog や like) 数 note_count を取得できます。

投稿情報を取得する関数のコード例です。引数には type (投稿タイプ:空文字だと全タイプを取得)、offsetminCount (反応数の閾値) を指定するようにしています。簡便のため取得したデータはその場で CSV としてレンダリングしてます。

function fetchPosts(type, offset, minCount = 0) {
    fetch(`${baseurl}${domain}/posts/${type}?notes_info=true&reblog_info=true&offset=${offset}&api_key=${api_key}`)
        .then(response => response.json()).then(json => {
            $("#offset").html(`offset:${offset}`);
            $.each(json['response']['posts'], function() {
                if (!this['reblogged_root_name'] && parseInt(this['note_count']) >= minCount) {
                    $("#posts").append(`${idLink(this['id'])},${this['date']},${this['type']},${this['slug']},${this['note_count']}<br />`);
                }
            });
        });
}

メインの処理では、投稿数取得のコールバックでループを回して全投稿分の処理を行います。1回の呼び出しごとに 500ms のスリープを入れています。

$(function() {
    getPostCount().then(count => {
        var offset = 0;
        while (offset <= count) {
            fetchPosts('', offset, 3);
            offset += 20;
            sleep(500);
        }
    });
})

僕は 2008 年頃から Tumblr を始めていて、2017年1月6日時点で投稿総数 6562 件でした(ほとんどがフォローしている人の投稿の reblog です)。測定してませんが全件分処理するのに体感で3分程度でした。

reblog じゃない自分が投稿した中で、3件以上反応があったものをタイプ別に集計すると以下のようになりました。

type post
link 7
photo 36
quote 126
text 5
video 4

やはり quote が母数も多いし、数が多かったです。上位結果は以下のようになりました。

quote:

post_url date note_count
http://reblog.kondoumh.com/post/116903557247 2015-04-20 2072
http://reblog.kondoumh.com/post/128707132367 2015-09-09 901
http://reblog.kondoumh.com/post/101674369492 2014-11-03 797
http://reblog.kondoumh.com/post/100990796202 2014-10-26 567
http://reblog.kondoumh.com/post/125576816117 2015-08-01 337
http://reblog.kondoumh.com/post/113365328582 2015-03-11 304
http://reblog.kondoumh.com/post/92392064267 2014-07-21 224
http://reblog.kondoumh.com/post/78287627384 2014-03-02 209
http://reblog.kondoumh.com/post/59828448393 2013-08-31 168
http://reblog.kondoumh.com/post/86791028732 2014-05-25 112
http://reblog.kondoumh.com/post/39637473249 2013-01-04 101

photo:

post_url date note_count
http://reblog.kondoumh.com/post/126011762237 2015-08-06 110
http://reblog.kondoumh.com/post/105334116637 2014-12-16 107
http://reblog.kondoumh.com/post/165475223402 2017-09-18 74
http://reblog.kondoumh.com/post/62335157286 2013-09-26 74
http://reblog.kondoumh.com/post/153985233752 2016-12-03 71
http://reblog.kondoumh.com/post/62874741172 2013-10-02 61
http://reblog.kondoumh.com/post/119751530162 2015-05-24 59
http://reblog.kondoumh.com/post/96782854287 2014-09-06 56

photo は天体ものが多い感じでした。

(5/6 追記)

ブラウザで動かしてたのを Node.js の CLI コマンドにしました。 最初 6700件ほどの処理を async await で同期的に書いたら、約20分かかりました。やはりある程度同時実行しないと時間かかります。定期実行して集計値のページ生成するなどの用途などでは AWS Lambda のようなサーバーレス構成には載せられない処理時間です。

ということで、フェッチ処理を並列化して、Promise.all() で待ち合わせるようにしたところ、15秒前後になりました。20件ずつなので、最大30多重ぐらいいく可能性があります。Tumblr API これぐらいなら平気で結果返してくれました。

github.com

*1:Twitter でもほぼ RTer と化していますが。

*2:投稿の 'author' が使えればいいのですがなぜか取れないので API Document には載ってない非公式な方法でしのぎました。