Quantcast
Channel: 永遠に未完成
Viewing all 102 articles
Browse latest View live

Google の Vim script Guide について言っておきたいこと

$
0
0

この記事は Vim Advent Calendar 2014の 25 日目の記事です。

Googleが、様々な言語に対する自社内でのスタイルガイドを公開しているのはご存知でしょうか。C++ のものJavaScript のものなどがあり、この辺りは割と有名かと思います。
では、Vim script のものがあるのはご存知でしょうか?
Googleは、Vim script について、2 つのガイドを公開しています。

前者がカジュアルユーザー向け、後者がヘビーユーザー向け、といった位置付けのようです。さすが、Googleがまとめているだけあって、なかなかポイントを抑えています。
ただ、これはあくまで Googleが社内向けに作ったもの。鵜呑みにしてはいけない、もしくは、一般の人が使う場合は参考にしない方がいい部分もちらほら見受けられます。
そこでこの記事では、この 2 つのスタイルガイドを見るにあたって注意すべき点をまとめようと思います。全て個人の見解です。引用に入っている訳は、私による勝手訳です。

全体について

maktaba が前提になっている

Googleが公開している、maktabaと言う Vimプラグイン向けのプラグインライブラリがあります。
これらのガイドでは、事あるごとに、Vimのこの機能は使わないで代わりに maktaba のこれを使え、のように指示してきます。
しかし、誤解を恐れずに言うと、maktaba はその仕組み上使うべきではありません。
ざっくり簡単に理由を言うと、maktaba は $ から移すことができない jQueryのようなものであり、別の言い方をすると、URL にバージョンが含まれていない Web APIのようなものです。今後互換性のない変更が入った瞬間に死亡する未来がありますし、今でも、maktaba のバグに依存した動作をするプラグインはバグが修正されると死にます。
と言うわけで、maktaba 云々と書かれている部分は華麗にスルーするのが良いです。

Google Vimscript Style Guide

Regular Expressions

Prefix all regexes with \m\C.

全ての正規表現は \m\C で始めること。

\mは 'magic'がオンの状態で正規表現の解釈を行い、\Cはパターン全体を大文字小文字を区別するようにします。
これは確かに誤爆を防ぐのには役に立ちますが、毎回指定するのはやや冗長です。
正規表現を受け取る Vim script の関数のうち、'magic'オプションが適用されるのは search() と searchpos() くらいです。
よく使う =~# も 'magic'の影響は受けません。
'ignorecase'オプションの影響を受けるのは、match()、matchend()、matchlist()、matchstr()、search()、searchpos()、searchpair()、searchpairpos()、substitute() になります。多いようですが、match() とその派生、search() とその派生、substitute() なので、系統としては 3 つくらいです。
この辺りはざっと調べたものなので、足りなかったり違っていたら教えてもらえると助かります。
自信がなければ \m や \C を付けておくのは悪いことではないですが、必須にするほどでもないかな、と思います。

Type checking

Use strict and explicit checks where possible.

可能ならば厳密かつ明示的な型チェックをしなさい。

is# などを使え、というのはその通りですが、全ての変数を使う前に型をチェックするのは冗長になりすぎます。
例えば Rubyを書いていて、全ての関数で、その引数について型のチェックをするコードを書くでしょうか? 書きませんよね。
期待した型でなければ、大体の場合は例外が飛ぶので、きちんと例外を処理すれば問題はないでしょう。たまに運悪く期待しない状態のまま先に進んでしまうこともありますが、その時はその時です。

Python / Other Languages

Python
Use sparingly.
Use python only when it provides critical functionality, for example when writing threaded code.
Other Languages
Use vimscript instead.
Avoid using other scripting languages such as ruby and lua. We can not guarantee that the end user's vim has been compiled with support for non-vimscript languages.

Pythonは慎重に使いなさい。他の言語は使ってはいけません。

はい。Googleなのでお察し、といったところでしょうか。Pythonだけ許可して他を許可しない理由が全く説明されていません。
個人的な見解を述べるならば、外部インターフェースは余程の必然性がない限りは使うべきではありません。理由は Googleが説明している通りで、ユーザーの Vimで使えるとは限らないからです。これは当然 Pythonにも言えることです。
ただ、あなたが書く Vim script があくまで自分向けのものであれば、書き易いように外部インターフェースを使うことは選択肢となりえるでしょう。他言語であればすでに揃っているライブラリを Vim script でわざわざ書き直すような真似は、一部の変態さんたちに任せて、あなたは使いなれた言語で使いなれたライブラリを使えばよいのです。
…私は変態さんなのでもう手遅れです。

Commands

In the plugin/commands.vim or under the ftplugin/ directory, defined without [!].

plugin/commands.vimか ftplugin/ ディレクトリに、[!] を付けずに定義します。

plugin/commands.vimに、と書いてますが、絶対にやってはいけません。
最近でこそ Vimプラグインプラグインマネージャでインストールして、runtimepath を追加していく方式が流行っていますが、本来は Vimプラグインは 1 つのユーザディレクトリにまとめていれていくもので、そのような運用も可能になっているべきです。
みんながみんな plugin/commands.vimにコードを書いたら、当然ファイル名が衝突します。
ちなみにどうやらこのファイル名のルールは maktaba によるもののようです。
[!] については、適切なコマンド名を付けていれば、ユーザの定義を上書きすることはほとんどないかとは思いますが、ここはどちらでも良いと思います。

Autocommands

Place them in plugin/autocmds.vim, within augroups.

plugin/autocmds.vimに、augroup 付きで定義しなさい。

Commands と同じファイル名の問題。

Mappings

Place them in plugin/mappings.vim, using maktaba#plugin#MapPrefix to get a prefix.

plugin/mappings.vimに、maktaba#plugin#MapPrefix を使って定義しなさい。

Commands と(ry
maktaba(ry

Naming

Prefix all variables with their scope.

全ての変数にはスコープのプレフィックスを付けなさい。

l: については無理に付ける必要はないと思いますが、一部の変数名が v: と衝突する可能性があるので、付けた方が安全ではあります。
私は省略する派です。

Google Vimscript Guide

こちらはヘビーユーザ向けということで、Style Guide の方の内容も含まれています。重複していない部分について言及します。

Structure

ここに書かれているものの多くは maktaba 前提の構成のようです。

Documentation

Use vimdoc.

vimdocを使いなさい。

この vimdoc というツールは、私もあまり詳しくないのですが、軽く調べてみた限りだと maktaba の構成に依存しているようです。
あとは変則的な help に対応しているのかがちょっとわかりませんでした。




と言うわけで、個人的に問題があると思う点を挙げてみました。
結構色々書きましたが、最初に言った通りポイントは抑えられていて、maktaba に絡まない部分はかなり参考になります。つまり諸悪の根源は maktaba…。


これで今年の Vim Advent Calendar は終わりです。でも、皆さんの Vimライフは始まったばかりです。それではまたいつの日か、未来でお会いしましょう!


無料で使える CI サービス 8 個まとめ

$
0
0

CI サービスをいくつか触ってみたのでまとめ。
今回の目的は、テストを実行すること。なので、ビルドやデプロイ辺りはちゃんとは見ていない。
ドキュメントで確認しただけの項目などもあったりするので、間違っていたらごめんなさい。教えてもらえると助かります。
ただ、これは記事を書いた時点での比較で、今後のサービスの変更に対応する予定はないです。

触ってみたサービス一覧

アルファベット順。

codeshipってのもあったけど、無料プランは月100ビルドまでとかで常用には耐えないと感じたので中身見てない。

機能比較

機能比較は全て無料プランでのもの。有料だと対応している場合でもここでは x にしている。
比較項目は私の独断と偏見で適当に選出した。

項目 AppVeyor CircleCI Drone IO Magnum CI semaphore shippable Travis CI wercker 備考
YAMLによる設定 × × リポジトリ内の YAMLファイルからビルド手順を設定できる
Web UI による設定 × × × Web UI でビルド手順のスクリプトを書くことができる
GitHub連携 GitHubリポジトリ一覧から新規プロジェクトを作れる
BitBucket 連携 × × BitBucket のリポジトリ一覧から新規プロジェクトを作れる
GitHub PR 対応 × × GitHubの Pull Request を自動でビルドしてステータスを返せる
ビルド環境キャッシュ × × × × × 複数ビルド間を跨ぐキャッシュ領域を利用できる
手動リビルド × *1過去のビルドを手動でリビルドできる
複数環境ビルド × × × × × 環境変数などで複数の環境に対してビルドできる
private なプロジェクト × × × ビルド状況などを private にできる(かなり未検証)
ビルド時間制限 30分 20分 15分 30分 60分 60分 50分 25分 無出力時間による制限が別途ある場合もある

YAMLによる設定の利点は、プロジェクト構成の変更とビルド手順の変更を紐付けることができること。
Web UI による設定の利点は、プロジェクトに直接関係ないファイルを置かなくて済むこと。特にファイルを置く権限がない場合などには助かる。

各サービスについて雑感

以下、かなり主観かつざっくりな雑感。

AppVeyor

http://www.appveyor.com/

.NET 向けの CI サービス。
.NET に特化した機能が色々使えるけど、重要なのは、テスト環境が Windowsであるということ。他に Windows環境での CI サービスを少なくとも私は知らないのでかなり貴重。.NET 製じゃなくてもこれを使えば Windows環境でテストができる。
設定のスクリプトは、Windowsのバッチファイル(.bat) と、PowerShellスクリプト(.ps1)の形式で書ける。PowerShell .NETのライブラリにアクセスできるので、外部からリソースのダウンロードなども可能。
ビルドトリガーが引かれると、新しいビルドは QUEUE に積まれて、実際にビルドが始まるまでに結構時間がかかる。

ビルド時間について、このページでは全てのプランは40分と書いてあるが、このページでは、Free、Professional、Premium は 30 分で Enterprise は 50 分と書いてある。どちらが正しいか不明。

CircleCI

https://circleci.com/

必要な機能は一通り揃っている印象。
YAMLでの設定において、各ビルドフェーズに、pre(フェーズ前)、override(フェーズのデフォルト動作を上書き)、post(フェーズ後)それぞれに対してスクリプトが書けたり、コマンド毎にカレントディレクトリや環境変数タイムアウト時間などを指定できるので、柔軟に設定できる。

Drone IO

https://drone.io/

Go 言語製の CI サービス。
他のサービスがビルド手順をいくつかに分割している中、Drone IO のビルド手順は1つのみと、とてもシンプル。
Pull Request 時のビルドは、がんばればできるらしいけど、それでもPR以外の普段の push で APIが叩かれたり、ビルドページから Pull Request のページへ飛べなかったりするので、できるとは言わない方が良さそう。

Magnum CI

https://magnum-ci.com/

現時点でまだ public beta の CI サービス。結構前からずっと beta な気がする。
使い勝手については特に問題はない。普通に使える。
beta なので、private リポジトリが無制限で使える模様。いつ beta が取れるのかは不明。

semaphore

https://semaphoreapp.com/

ビルド中にスレッドが使えるのが特徴。ビルドパイプラインの各コマンド単位で、どのスレッドで走らせるか指定できる。無料で 1 ビルド中に 2 スレッドまで使える。
あとはプロジェクト構成を見て、一般的な構成の場合は自動で検出してビルド設定を自動で終わらせてくれるらしい。私が試したプロジェクトは一般的な構成ではなかったので、どこまでやってくれるのかよくわかってない。

shippable

https://www.shippable.com/

Travis CI と互換があり、.travis.yml ファイルが置いてあるとそれを認識してビルドを行ってくれる。ただ、どこまで互換があるのかは不明。Travis CI には language に generic が指定できるのだけど(ただしドキュメント化されていない)、shippable では指定できなかった。
Web UI が開かれるまでに結構時間がかかる。

Travis CI

https://travis-ci.org/

恐らく今回まとめた中では一番有名な CI サービス。
GitHub限定とは言え、テストをするのに必要な機能は十分揃っている。鉄板。

wercker

http://wercker.com/

他の CI と比べても変わった、box と step という特徴がある。
box はテストの実行環境。ユーザーが作成したものを wercker ディレクトリに登録しておけば、誰でも使えるようになる。特定のツールがインストール済みの環境などを作っておけば、ビルド時間が短縮できる。標準でいくつか用意されているので、それらを使ってももちろんよい。
step はビルドの手順の1つ。bashで言う1つのコマンドで、wercker ではこの step のリストをビルド手順として指定する。step は、特定の動作を抽象化してまとめたもので、Amazon 3S との同期とか、npm install とか、そういう感じのが1つの step として登録されている。最悪 script step というのがあるので、これで bashでやってもよい。この step もユーザーが自作できる。

まとめ

無料でもこれだけの選択肢があるというのがすごい。
よりどりみどりなので、各自のユースケースにあった CI サービスを選んで使うといいと思う。

*1:ブランチ最新のみ

Ruby の Hash で値だけ map で変換したかった

$
0
0
hash = {a: 1, b: 2, c: 3}
hash2 = hash.map {|k, v| [k, v * 2] }.to_h
p hash2  # => {a: 2, b: 4, c: 6}

めんどくさい。Scalaには mapValuesというのがあるらしい。

Rubyで書くならこうかな。

classHashdefmap_values(&block)
    dup.map_values!(&block)
  enddefmap_values!(&block)
    update(self) {|_, v| block.call(v) }
  endend


hash = {a: 1, b: 2, c: 3}
hash2 = hash.map_values {|v| v * 2 }
p hash2  # => {a: 2, b: 4, c: 6}

ググる似たようなはちらほらあるっぽい。Rubyにも標準で欲しかった。

master への push を禁止するローカル git hook の正しい書き方

$
0
0

GitHubなどで Pull Request ベースで開発をしていると、master には間違っても push したくないわけです。
GitHub側には残念ながら master への push を禁止するような設定はできないので、仕方ないのでクライアント側の Hook で対応しようってことになり、この方法についてググるこことかこことか、いくつか方法を紹介しているページが出てくるんですが、どれもやり方が間違っている*1ので、正しい方法を紹介。

何がまずいのか

上記に挙げた方法では、細かい部分は違ってたりするけど、git symbolic-ref HEAD を使って現在ブランチを見て、master だったら push を禁止する、という方法を取っている。
しかし、push はカレントブランチから行われるとは限らない。dev ブランチにいるときに git push origin master とすれば、当然 master ブランチが push される。この場合上記の方法だと防げない。他にもありがちなパターンだと、git push origin --all などでも master が push される。

正しい方法

pre-push hook を以下のような感じにする。

#!/bin/bashwhile read local_ref local_sha1 remote_ref remote_sha1doif [["${remote_ref##refs/heads/}"="master"]];thenecho"Do not push to master branch!!!"exit1fidone

標準入力から push 先のブランチ名の情報なんかがくるので、そこをチェックする。詳しく知りたい人は man githooks の pre-push の辺りを見るとよい。

なぜ間違った方法が出回っているのか

恐らくだけど、master ブランチへのコミットを禁止する pre-commit のスクリプトが流用されたのだと思う。pre-commit の場合は、現在ブランチを見ればいいので、それで正しい。それを pre-push へそのまま適用しようとしてはいけない。

ところで

そもそも GitHubさんがサーバ側で master への push を禁止できる機能を入れてくれると色々と捗るのでそういう機能是非入れて欲しい。なんでないのー。

*1:少なくとも私には正しい方法を記述したページを見付けられなかった

OmniSharp.vim のメンテナになりました

$
0
0

http://i.gyazo.com/648e0bbd21949a25313e8ab983e4df04.png
https://github.com/OmniSharp/omnisharp-vim
顔アイコンの中にマンボウアイコンを潜り込ませることに成功しました。壮観ですね。
問題の報告や機能要望などは私に直接言ってもらっても大丈夫です。日本語でOK。サーバ絡みだと対応は難しいかもしれないですが、善処します。
GitHubの Issue の方は世界中の人が見ているので、あちらに書く場合は英語でお願いします。

漢字パズルを解く word-finder というのを作った

$
0
0

例えば、以下のような問題があったとします。

全  全
    ↓  ↓
中→□→□→結
    ↓  ↓
    曲  金

□に入る漢字を答えろ

この手の問題を解く場合、自前の知識の中から、時には勘も交えて総検索することになります。
ヒラメキと言えば聞こえはいいですが、別に考え方を変えたりして解ける問題ではないので、やることはただひたすら検索です。
なら機械にやらせてもいいのでは、ってことで、こういう問題を解くやつを作りました。
とりあえず動くレベルで、仕様とか見た目がかなり雑ですが、動くので公開します。

http://thinca.github.io/word-finder/

使い方

上記の URL を開いても、(少なくとも記事公開時点では)謎のフォームと[検索]ボタンがあるのみで、意味不明です。
というわけで使い方。
まず、わからない部分をアルファベットに置き換えます。

全  全
    ↓  ↓
中→A →B →結
    ↓  ↓
    曲  金

今のところ置き換えられる文字は半角英数字と一部の記号のみです。
そして、ここから拾える単語を列挙します。

全A
中A
A曲
全B
B結
B金
AB

この単語のリストをフォームに貼り付けます。
そして検索ボタンを押すと…答えが出ます!
ちなみに単語の文字数としては 2-5 文字まで対応していますが、合成単語とかは出ないかもしれないです。詳細は下記の「辞書について」を参照。

なぜブラウザなのか

スマホから使いたかった。

辞書について

できればフリーの国語辞典でもないかなーと思って探したんですが、単語の一覧を簡単に扱えるようなものは見付けられなかったので、最終的に SKKの辞書ファイルに落ち着きました。
SKKの辞書から必要な部分を切り出して使っています。なので、SKKの辞書に載っていない単語は検索できません。
ところで SKKの辞書データって GPLっぽいのだけど、データが GPLの場合にその扱いについて調べたけれど、GPLはソフトウェアに適用されるものらしく、データの場合はよくわからなかった…。
word-finder を GPLにしないといけないならどうせコードは公開しているので問題はないのだけど、なんか気持ち悪いので詳しい方いたら教えていただけると助かります。

そう言えば完全に余談だけど、SKKの辞書って未だに EUC-JP なんですね。そろそろ UTF-8とかにしてもいいのでは…。辞書に登録できない文字とかも出てきちゃうだろうし。

今後の課題

Web ページを作るということを普段しないので、習作も兼ねているので、作りがだいぶ雑です。CSSすらないし…。

  • 使い方が意味不明なのでせめて説明をページ内に入れたい。
    • スペース取るのは邪魔なのでポップアップするリンクがあると良さそう。
  • 見た目もう少しマシにしたい(案はない)。
  • 辞書を加工するツールをなんとなく Rubyで書いたけど、ブラウザ側のコードが JavaScript(正確には CoffeeScript)なので、統一する意味で nodejs 辺りで書き直したい。
  • jQueryを使っているけど、最近だとあまりよろしくないらしいとの噂なのでなんか置き換えるなどしたいかも。
    • この程度の規模なら別によいって話もあるかもしれないけどよくわかっていない。
  • 読み(カタカナ)の辞書を足せばクロスワードパズルにも使えそうな予感。

Yokohama.vim.reboot #6 に行ってきた

$
0
0

Yokohama.vim.reboot #6に行ってきた!
最近は勉強会自体あまり行けてなくて、それなのに行っても感想記事サボっているので反省…。久々に書く。

アイスブレイク

Vimに関するキーワードが書かれたカードを、自分には見えない(というより見ない)ように、他の人には見えるように首から下げる。
そしてペアを組んで、軽く自己紹介したあと、互いに自分のカードに書かれた内容について、はいかいいえで答えられる質問をしてって、自分の持ってるカードに書かれたキーワードを当てる、というゲームをした。ペアは適当な時間毎に組替える。
これが意外にむずくて、なかなか当てられない…。キーワードは初心者向けと上級者向けに分かれていたので、私は空気を読んで上級者向けのを取ったのだけど、上級者向けのワードはそもそも初心者の人に質問しても相手がその単語についてよくわかっていなくて曖昧な答えが返ってきたりして、そうなることも計算に入れつつ質問を考えて答えを探すのがめっちゃむずかしかったけど楽しかった。
かなり盛り上がって、予定の時間より長くなったけどめっちゃ良かった。ちなみに私のキーワードは view でした。view コマンド使わないなぁ…。

KazuakiM さんの発表

Vimを使うようになった軌跡みたいなお話。Vimにデレていく話はいい話ですね。
ちなみにサクラエディタを使ってたという話だったけど、私も以前はサクラエディタ使ってました。よさ。

vimrcソースリーディング

各テーブルに分かれて vimrc 読んだりなんだりした。
他のテーブルがどういう感じだったのかは知らないのだけど、私のところのテーブルは3人で、私以外の二人の vimrc を順番に読んでいって改善ポイントとか探したり、改善のための編集操作で、こうした方がいいよ、とかこういう方法があるよ、みたいなアドバイスをしていくみたいな偉そうなアレをしてました。マンボウさん偉そう。
ガッツリ読んで改善して、みたいなことをしていたので、予定のタイムテーブルにあった、スクラッチからの vimrc 構築は結局やらなかった…。希望者が少なかったのもあるけど、スクラッチからはやはりなかなか難しい感じがある。

懇親会

ビアバッシュで、寿司とかナン+カレーとかチキンとか食べつつおしゃべりも少ししつつ割ともくもくと食べてた。
食べ終わって、勢いでやるって言ってあったライブコーディングをすることになったんだけど、ネタは考えてなくもなかったんだけど正直みんなに楽しんで貰えるネタか自信がなくてその場でみんなにネタ聞いたりしてやった。
その結果、とあるsyntax定義プラグインが微妙なので直すのをやって欲しい、みたいな話があって始めたのだけど、なぜか Vimがエラー出しまくって、調査をした結果 Vimのバグっぽいということがわかり、そのIssueを登録するということをして、当初の目的は忘れられてライブVimデバッギングになってしまった…すまぬ…。
これはこれで滅多に見られないもの見せられたしよかったかな感はあるけど、所詮結果論だし、グダってしまったのは本当に申し分けない。その場でお題を募集なんてすると下調べもないもんだからどうやってもグダるし、やはりやるときはちゃんと自分でお題を用意しとこうって思った。次に活かしたい。

まとめ

次回も行きます!

Vim script で AtCoder に参戦する方法

$
0
0

先週、進捗キャンプという知り合いで集まって進捗を出す会に行ってきて、そこで @さんと表題の件について色々話した。
その後個人的に手法をカイゼンしたりしたので、結果をまとめておく。

AtCoderとは

http://atcoder.jp/
私自身も「とは」と言って語れるほど詳しくはないので簡単に説明すると、主に日本人向けの競技プログラミングサイト。
問題は全て日本語で、定期的に様々なコンテストが開催されている。問題の難易度が低い初心者向けのコンテスト(AtCoder Beginner Contest 通称 ABC)なんかもあるので、競技プログラミングの入口としては最適だ。

AtCoderの対応言語

競技プログラミングでは、ソースコードを提出し、提出されたコードが正しく動くかどうかサーバ側で実際に動かして検証を行う。つまり、サーバ側に各言語の処理系が必要であり、競技プログラミングで使用できる言語はその点で制約がかかる。
どの言語が使えるかは競技プログラミングによって様々であるが、AtCoderはかなり多くの言語に対応している。
しかし、Vim script は対応言語には含まれていない。
それもそのはず。Vim script は言語としてマイナーという点を除いても、とある問題がある。

競技プログラミングの問題形式と Vim script

競技プログラミングにおける問題は、多くの場合、標準入力と標準出力を使う。
標準入力から問題のデータを受け取り、問題を解いて、結果を標準出力に出力させる。
AtCoderも例に漏れずこの形式である。
標準入出力は多くの言語が標準で扱えるので、この形式にすることで多くの言語に対応することができるためだと思われる。
しかし、Vim script はテキストエディタVimを拡張するための言語。標準入出力を直接扱うことは、できない。

ではどうするか

AtCoderの対応言語の1つに、Bashがある。
Bashは、それ自身にもそれなりの演算能力はあるが、どちらかと言うと外部プログラムを呼び出す能力に長けている。
実際、awkや bc なんかがよく使われたりするらしい(よく知らないけど)。
つまり、この Bashの環境に Vimが入っていれば、あとは標準入出力を Bash側で面倒を見ることによって、Vim script が使えることになる。
試したところ Vimはちゃんと入っているようだった*1。これで Vim script で問題が解ける。

Vim script で問題を解く

AtCoderには練習用のコンテストがあるので、そこにある練習問題を解いてみる。
http://practice.contest.atcoder.jp/tasks/practice_1

vim -u NONE -i NONE -N-n-e-s-S<(cat <<EOFfunction! s:main(input) abortlet a = a:input[0]let [b, c] = split(a:input[1], '')let s = a:input[2]return(a + b + c) . '' . sendfunctionlet s:input = getline(1, '$')enewput =s:main(s:input)1 delete _%printEOF)<(cat)

結果はこちら
ちゃんと解けてる。

何をしているのか

まず、このコード自体は Bashであるが、事実上その大部分は Vim script である。
ちょっとずつ分解していくと、まず vimを起動するコードは Vim script の部分を省略すると以下のようになる(... の部分が省略部分)。

vim -u NONE -i NONE -N-n-e-s-S<(...)<(cat)
  • -u NONE
    • vimrc ファイルを読み込まない。
  • -i NONE
    • vininfo ファイルを作成しない。
  • -N
    • vi 互換モードをOFFにして(つまりVimとして)起動する。
  • -n
  • -e -s
    • バッチモードで起動する。詳細は割愛。(気になる人は :help -s-ex を参照)
  • -S {ファイル}
    • 起動後にファイルを Vim script として実行する。
  • <(cat)
    • Vimで開くファイルの指定。<(...) はプロセス置換という bashの機能で、コマンドの結果をファイルとして渡すことができる。

さて、Vimを起動していることはわかったので、次は Vim script 部分。

function! s:main(input) abort
  leta=a:input[0]
  let [b, c] =split(a:input[1], '')lets=a:input[2]
  return(a + b + c).''.sendfunctionlets:input =getline(1, '$')enewput=s:main(s:input)1delete _
%print

ちょっとずつ見ていく。

function! s:main(input) abort
  leta=a:input[0]
  let [b, c] =split(a:input[1], '')lets=a:input[2]
  return(a + b + c).''.sendfunction

わかりやすくするため、問題を解く部分を関数に分けた。
引数の input は、入力のテキストが行単位で配列で渡ってくる。
結果を文字列か、行単位の配列で返す。

lets:input =getline(1, '$')

入力はファイルとして渡ってきており、バッファに開かれている。
バッファの全行を配列として s:input に保存している。

enew

output 用の新しいバッファを開く。

put=s:main(s:input)1delete _

結果をバッファに展開している。
空のバッファに put でテキストを置くと1行目に空行が残ってしまうので、delete でこの余計な空行を消している。

%print

バッチモードの Vimでは、print などのいくつかのコマンドの結果は標準出力へ出される。
%print でバッファ全体を標準出力へ結果として出力している。
ちなみにこの方法だと、最後に改行のない出力が行えない*2が、大抵の競技プログラミングの問題は最後に改行を出力させるので、問題になることはないだろう。

解く環境を整える

テンプレート

こうして見るとわかる通り、実際に触るのは s:main() 関数の部分だけであり、他の部分はテンプレートだ。
テンプレート系のプラグインを使って、テンプレート化しておくと便利だろう。
ちなみに私は template.vimを使っている(宣伝)。

Vim script 部分だけ編集する

ファイル全体としては Bashだけど、編集したいのは Vim script だ。main の部分だけを、filetype=vimで編集したい。
そんな時に便利なのが partedit.vimだ。
バッファの一部を別のバッファで開き、別のファイルタイプで編集できる。保存すると元のバッファに適用される。

https://i.gyazo.com/14a70ff2a7148b9e1507170bda083710.gif

上の動作例では :Partedit コマンドを引数なしで動かしているが、そうするためにはオプションの設定が必要だ。

" 部分を編集するバッファを開くコマンドの指定。これは縦分割したい場合の例 (デフォルトだと現在のウィンドウにそのまま開かれる)letg:partedit#opener ='vsplit'" 部分を編集するバッファの filetype。デフォルトだと元のバッファと同じ filetype が適用される。letg:partedit#filetype='vim'

ファイルタイプは常に同じだと別のシーンで使いたい場合に困ると思うので、localrc.vimなどを利用して、b:partedit_filetype を設定するといいだろう。

テストケースを実行したい その1

答えが正しいか、提出する前に手元で実行して確認したいだろう。
開いているファイルを実行したい、と来れば、quickrun.vimが便利だ。
問題の入力を標準入力で与える必要があるが、幸い quickrun.vimは標準入力にも対応している。input オプションを設定すればよい。

" input.txt ファイルの中身を標準入力として使う
QuickRun -input input.txt

" = で始めることでファイルではなく入力文字列を直接与えられる
QuickRun -input =input-text
" i レジスタの中身を標準入力として使う
QuickRun -input =@i" b:input 変数の中身を標準入力として使う
QuickRun -input =%{b:input}" 事前に設定しておけば毎回指定する必要はないletg:quickrun_config ={'_': {}}letg:quickrun_config._.input ='=@i'letg:quickrun_config._.input ='=%{b:input}'" 実行する際に変数に値を入れれば OKletb:input ="1\n2 3\ntest\n"

print デバッグするには、put コマンドを使えばよい。
最終的なバッファの内容が出力結果になるので、put コマンドでバッファに行を足してやる。

lethoge='debug'put=hoge
" put の中では " はコメント扱いになり使えないので注意put="foo"これはコメントになるので動かない
put=\"foo\"  " これなら動く
テストケースを実行したい その2

実は、もっと楽な方法がある。ここで s:main() を切り分けておいたのが役に立つ。
単純に s:main() を呼んでしまえば良い。

function! s:main(input) abort
  leta=a:input[0]
  let [b, c] =split(a:input[1], '')lets=a:input[2]
  return(a + b + c).''.sendfunctionecho s:main(['1', '2 3', 'test'])

これで OK だ。ただし、この状態で Bashとしてこれを実行しても結果を見ることはできない。
しかし先ほどの partedit.vimで、このバッファは Vim script として独立している。そう。quickrun.vimを使えばよい。このバッファはファイルとして存在していないが、quickrun.vimであれば実行可能だ。

こちらの方法で print デバッグしたい場合は、echo コマンドを使えば OK だ。わかりやすい。

ちなみにこれらの echo の行は、Bashとしての実行結果には一切影響を及ぼさないので、そのまま投稿することも可能だが、当然実行時間は長くなってしまうので注意が必要だ。

最後に

Vim script で AtCoderに参加する方法について紹介した。
今回の例では出てこなかったが、当然 main 以外の関数を定義することもできる。
また、よくある操作については vital.vimのコードが参考になる。Data.ListData.StringMath辺りには便利関数が揃っている。NYSLなので、コピペして使ってもまったく問題ない。是非活用して欲しい。
Enjoy Programming!

*1:軽く調べてみたところ、練習用コンテストの Vimのバージョンは 7.3.429 だった。Ubuntu 12.04 の Vimがこのバージョンなので、この環境を使っている可能性が高い。コンテストによっては環境が異なる可能性があるので注意。

*2:一応別の方法で回避はできる。


イカリングを閲覧できる ikaring.vim を作った

$
0
0

Splatoon してますか? 本日また大きめのアップデートが入って、まだまだ熱は冷めそうにないですね。
さて、この Splatoon 専用の SNSとして、イカリングというサービスがあります。

イカリング: https://splatoon.nintendo.net/

フレンドのオンライン状態を確認できたり、フレンド内での週間ランキングが閲覧できたり、自分やフレンドの装備や各ブキの塗り面積が確認できたり、ステージのスケジュールを知ることができて、とても便利です。
とても便利なのでいつでも見れると嬉しいですね。
というわけで Vimから見れるようにしました。

https://github.com/thinca/vim-ikaring

使い方

:Ikaringコマンドを実行すると開始できます。
初回は、Nintendo Network ID とパスワードを訊かれるので入力します。
ログイン後はクッキーをローカルに保存するので、セッションが切れるまでは再度入力する必要はありません。
もしくは以下のように変数を設定しておけば自動的に接続します。

letg:ikaring#username ='thinca'letg:ikaring#password ='******'

開くと以下のような画面になります。

…これはたまたま誰も遊んでないだけであって、フレンドがいないわけじゃないんだからね!
というわけでランキング画面を開いてみます。

:Ikaring ranking

ちゃんとフレンドいますね。
ナワバリバトルのポイントが0になってますが、これは単に勝率が0%なだけです。バグではないです。
次にプロフィール画面を開いてみます。

:Ikaring profile

出ましたね。ブキをとっかえひっかえしているせいでウデマエが全然上がりません。
一番下を見ると、塗りの合計も見れます。

ちなみに、フレンド画面やランキング画面でユーザー名の上で を押したり、:Ikaring profile [ユーザー名] (補完あり) を実行すると、フレンドのプロフィールが見れたりします。

最後にステージ情報です。

わかりやすい。

苦労した点について

実はこのプラグイン、8月上旬に作り始めて、早い段階で8割方できてたんですが、エラー処理とかその他細かい部分のブラッシュアップをしようと思ってたらこんな時期になってしまいました…反省…。
さて、ここからは作る上で苦労した点について書いていきます。

ログイン

当然ですが、イカリングには APIなんてものはありません*1
じゃあどうするかというと、スクレイピングになります。
最初に試しに Rubyで Mechanize を使ってやってみたところ、当然のようにログインしてログイン後のページのデータが取れました。便利。
しかし、今回作るのは Vimプラグインなので、Vimでやりたいわけです。Rubyに頼るわけにはいかない。
というわけで、スクレイピングするようなライブラリを、今回やりたいことができる最低限の機能で作りました。
まだリリースしてませんが、vital.vimのライブラリとして作ってあります。ikaring.vimに含まれているので、気になる人は見てみてください。
この件についてはリリースも含めて後日また書きます(たぶん)。

ギアの名前

イカリングですが、ブキやギアは基本的に画像でしか表示されていません。名前のリソースが一切ないのです。
画像の方はどうやらブキやギアに対してハッシュ値の ID が振られていて、URL にはこの ID が使われているようです。
なので、ID とブキ/ギアの対応さえわかれば、表示できます。しかし、この ID を知るには、イカリング上で各ギアを表示する必要があるのです…。
ブキに関しては、実はフレンドにバトルの予定を知らせる機能の部分に一覧がありました。そもそもブキは入手も簡単なので ID を知るのは難しくないです。
ギアに関しては、1つずつ調べていくしかありません。ギアの ID を知るには、ギアをイカリング上に表示する必要があり、つまり自分もしくはフレンドの誰かが該当ギアを装備していなくてはいけません。
なので私は、ゲーム上で入手可能なほぼ全てのギア*2を入手し、装備してバトルを行い、数分後にイカリングに反映されているのを見ては ID をチェックする、という作業を繰り返して、ほぼ全てのギアの ID を調べることに成功しました!やった!!!
…と思ったら、そのうち来るとは思っていたけど、本日、無事アップデートで新ギアが追加されました。本当にありがとうございました。
もう私一人で全て調べるのは無理です*3
もしあなたが ikaring.vimを使っていて、本来ギアが表示されるはずの部分にハッシュ値が表示されたら、ぜひその ID とギアの名前を以下の Issue にコメントして教えてください。フレンドの持ってる名前の知らないギアの場合などもあると思いますが、しばらくすれば攻略 Wikiなんかで画像付きで名前が調べられると思うので、そちらも合わせてご確認頂けると助かります。ご協力をお願いします!

https://github.com/thinca/vim-ikaring/issues/1




と言うわけで ikaring.vimを作った話でした。イカよろしく〜

*1:一部の情報はログイン後なら JSONで取得できたので、そこは楽でした

*2:まだランク50になってないのででんせつのぼうしだけ持ってない

*3:もしくはとても時間がかかります。コンプガチャつらい

VimConf 2015 に行ってきた

$
0
0

VimConf 2015に行ってきた。
昨年は主催的ポジションからの参加だったのだけど、今年は割と一般参加的ポジションで、一応スタッフって枠にはなってたけど大したことはしてないし、ラクさせてもらいました。

というわけで各発表についての感想を雑につらつらと。

Vimのgitへの移行について - @

まさかのスライドなし発表すごすぎた。
GitHub移行は外からだと割とすんなり決まった印象があったけど、やはり裏では色々あったんですね。

deoplete ~ The dark powered auto completion plugin for neovim ~ - @

Shougo さんのバイタリティは相変わらずすごい。…すごい。

私はどのようにVim scriptを書くか? - @

Vim script 入門的な内容。これで Vim script 書く人増えるといいなー。
発表資料がすごく凝っててすごかった。

Hacking Libcall and Java - @

「一般的」の定義について考えさせられる内容だった。もはや持ちネタと言えるレベル。
発表中にツッコミが入ったりしてすごかった。

Vim on Browser - @

ブラウザ上で Vimを動かす話。
プラグインのデモがブラウザでできるってのはかなり便利そうさを感じた。
feature=small でしか動かせないのが残念だけど、普通に動いているのでとにかくすごい。

Vim + Clojure - @

VimClojureを書くのに便利なプラグイン群の紹介。
今年も去年同様 Civilization 5 の話題が盛り込まれており、すごかった。

Introduction to OmniSharp.vim - @

OmniSharp.vimについて話した。
たいがいキョドってるのでちゃんと伝わったかすごい心配…。

海外のVimmerが開発したVim pluginの紹介 @

One more thing すごい。

ぼくのかんがえたさいきょうのぷらぐいん vim-gita - @

gita 存在は知ってたけど、改めて見るとやはりすごい便利そうだった。
プログラマじゃないのにこんなの作れるなんてすごい。
まだまだ開発版っぽいので今後はもっとすごくなるらしいので期待したい。

Vim script版 power-assert について - @

power-assert、仕組みまでは理解できても、実際に作ってしまうのはすごい。

切り刻め!HTML - @

フロントエンド周りはあまり詳しくないので、必要になったときにすごく参考になりそうな情報満載だった。

ヘルプを読む - @

逆引きヘルプの提案がすごく便利そうだった。

vim-jpのvimhelp, reading_vimrcのホスト関連のお話 - @

Docker やらその周辺の使いこなし具合がすごかった…。

5年間Yokohama.vimをやってみて感じた事 - @

継続されている Yokohama.vimは本当にすごい。次回も是非参加したいです。

AppVeyorを使ってみよう @

vimproc については私自身はバイナリが欲しかったので、テストはとりあえずいっか、って思っていたのを k_takata さんがやってくれて、すごくありがたかったです。
Cygwinが動かないのは本当に謎…なんなんだ…。

まとめ

つまりまとめると、すごい。

最後に

VimConf は多くの方の協力で成り立っています。まとめ役をやってくれた @さん、会場提供をしてくれた株式会社ミクシィさんと、その連絡役をしてくれた@Kuniwakさん、発表者の皆さん、スタッフの皆さん、そしてもちろん参加してくれた全ての皆さん、ありがとうございます!
VimConf は恐らく来年も開催されるとは思いますが、イベントをよりよくしていくために、以下のページで KPTをやっています。(KPTはふりかえり手法の1つで、詳しくはググってください google:KPT)

KPT for 2016

この KPTは特にスタッフ専用ということはないので、一般参加者の方でも、なんなら参加したかったけどできなかった方でも、Keep だけでも Problem だけでも Try だけでも、なんでもいいので書いてみてください。
みんなの意見がよりよい VimConf を作っていくはずです。

Vim に追加された assert 系の関数の紹介

$
0
0

この記事は Vim script Advent Calendar 2015の 3 日目の記事です。

はじめに

先月末に、Vimの組み込み関数に assert 系の関数が追加されました。
今回はこの関数について紹介します。

歴史

割とどうでもいいので読み飛ばし可です。

2015-11-29 Vim 7.4.944

assertEqual()、assertTrue()、assertFalse() が追加されました。また、一緒に使うための v:errors も追加されました。

しかし、関数名について苦情が多く出ました
Vim script の組み込み関数の多くは、単語の区切りがなく1単語です。例えば deepcopy() や matchlist() などです。
一部の関数には _ が使われており、has_key() や complete_add() があります。
そして中には大文字を含む関数もありますが、今のところそれらは全て ID と言う単語に使われており、synID() や diff_hlID() などです。これらは例外と言えそうです。
つまり今まで camelCase が使われていなかったのにも関わらず突然 camelCase の関数が追加されたので、それはさすがにおかしいという話になりました。

2015-11-30 Vim 7.4.945

assertEqual()、assertTrue()、assertFalse() がそれぞれ assert_equal()、assert_true()、assert_false() にリネームされました。
また、先の話で別途提案された、各関数にエラー時のメッセージを渡すためのオプショナルの引数を追加するパッチが適用されました。
わずか1日でのスピード対応、ドキュメントもテストも修正されて完璧…と思いきや…肝心の実装が適用されておらず、関数名は変わっていませんでした…。

2015-12-01 Vim 7.4.946

無事実装も適用され、assert_equal()、assert_true()、assert_false() にリネームされました。

2015-12-03 Vim 7.4.950

一通り解決されたかに思いましたが、変数 v:errors が初期化されていないという問題が発見されました。
現在 vim_dev にパッチを投げています
恐らくすぐに適用されると思います。
適用されました

使い方

仕組みは単純です。
v:errors は配列になっていて、各 assert 関数が失敗すると、v:errors にメッセージが文字列として追加されます。
なので使用前にまず v:errors を初期化します。

letv:errors = []

続いて適当に assert 系の関数を呼びます。

function! Test() abort
  letactual=2+2call assert_equal(5, actual)endfunctioncall Test()

v:errorsを見ると、失敗の結果がわかります。

echov:errors" => ['function Test line 2: Expected 5 but got 4']

結果のメッセージの : の左側にある文字列は expand('') の結果に行番号の情報を足したものです。
メッセージの右側には失敗時の値が出ます。
また、assert 系の関数には追加でメッセージを渡すことができ、渡すと : の右側はこのメッセージが表示されます。

letv:errors = []
function! Test() abort
  letactual=2+2call assert_equal(5, actual, 'test fail!')endfunctioncall Test()echov:errors" => ['function Test line 2: ''test fail!''']

終わりに

見てきたように、非常に簡単な仕組みのもので、なんなら Vim script で自作もできそうな仕組みになっています。
今後、Vim本体での Vim script 周りのテストはこの関数が使われるようになるようです。
本体以外でも、簡易なテストが書きたい場合には使えるかもしれません。

Boost.勉強会 #19 東京 に行ってきた

$
0
0

C++まったく書いてないけどなぜか Boost.勉強会 #19 東京に行ってきたよ。
C++の最近の動向に軽く触れる感じでゆるーく感想書いてく。C++よくわかってないのでよくわからない感想しか書けません。

Boostライブラリ一周の旅 1.59.0-1.60.0 - @

資料: http://www.slideshare.net/faithandbrave/boost-tour-1600
資料(マージ版): http://www.slideshare.net/faithandbrave/boost-tour-1600-merge

いつものやつ。
Boost.Test v3 で Power Assert 入ったのだいぶ強そうだった。

Effective Modern C++C++ Core Guidelines - @

資料: http://www.slideshare.net/ShintarouOkada/boost19-effective-modern-cc-core-guidelines

Effective Modern C++邦訳版を査読した話と、CppCoreGuidelinesの話。
査読報酬で具体的な話が聞けたのだいぶ良さがあった。
CppCoreGuidelines は lint を提供することを想定しているとのことで、使えるようになったらとても便利そう。
詳しくない言語を書くとき、良い書き方なのかいつも気にしながら書こうとしてしまうのでそれだけでかなり時間がかかってしまうのだけど、lint があると安心して書いていけそう。

SIMDのゆるい話 - @

資料: http://www.slideshare.net/krustf/avx-simd

ゆるい話…なるほどわからん、という感じだった。すまぬ。

「女性のためのC++コミュニティ Ladies++ meetup #1」の紹介 - @

資料: http://www.slideshare.net/cocodrips/c-ladies

女性のためのC++コミュニティ Ladies++ meetup #1の紹介。
コミュニティが始まったばかりで人脈があまりないので女性 C++er を紹介して欲しいとのことです。

クロスプラットフォームマルチメディアライブラリSDL2の紹介 - @

資料: http://www.slideshare.net/nyaocat/sdl2

SDL2の紹介。

いつの間にかライセンスが zlib になっていたのと、Emscriptenでブラウザにも対応していたの知らなかった。

クソザコ鳥頭が非順序連想コンテナに入門してみた - @

資料: http://www.slideshare.net/kariya_mitsuru/ss-55842496

非順序連想コンテナが仕様である処理時間を定数時間にするための実装の苦労がおもしろかった。

expectedによるエラーハンドリング - @

資料: http://www.slideshare.net/faithandbrave/error-handling-using-expected

expectedの紹介。
Haskellの Either に成功/失敗の明確な意味を持たせたものと解釈した。
単に成功値か失敗値が欲しいというだけなら、variant でも目的は達成できるのかもしれないけど、インターフェースが成功/失敗に特化して作ってあるし、何より明確な意味があるのは便利。

Boost.Configについて - @

資料: http://www.flast.jp/article/boost-19-tokyo/index.html

コンパイラC++のバージョンの差異を吸収するための中の人が使うライブラリの話。
なんというかやはり苦労してるんだな…という感じ。

メモリモデル再入門 - @

資料: https://docs.google.com/presentation/d/1ClVZvXo8lj7TE66hZ0eqNyVc1DBcRciJRXUxukhOb2k/pub#slide=id.p

スレッドとか Data Race とかの話。誰でもわかる基本的な例から徐々に複雑な例にしていく解説が上手いなと思った。
なかなか面白い話だったのでスライド最後まで完成させてほしかった…。

全体的な感想

割とわからないことだらけかなーとも思ってたけど、面白いセッションも結構あって良かった。
相変わらず C++書く機会ないですが、C++は割と好きな言語なのでまた機会があれば参加したいです。

全角スペースを可視化するプラグイン zenspace.vim を作った

$
0
0

プログラミングをしていると、混ざっていると困る全角スペース。
可視化するように設定を書いている人も多いんじゃないでしょうか。
実際ググると、全角スペースを表示するための設定がたくさん出てきます。私も vimrc に設定書いてました。
でもこれ…みんなやってるなら、もうプラグインでよくない?
ってことでプラグインにしました。

zenspace.vim - Show Ideographic Space (a.k.a. Zenkaku Space).
https://github.com/thinca/vim-zenspace

全角スペースを表示するためだけのプラグインです。(画像内のタブの表示は 'listchars'によるもの)

デフォルトでは 'list'オプションの値に連動して、可視/不可視を切り替えます。なので、'list'オプションをオンにしてください。

setlist

'list'オプションとかいいから常に表示しろよ、って場合は g:zenspace#default_modeを設定してください。

letg:zenspace#default_mode ='on'

zenspace.vimは、常に表示する "on"、表示しない "off"、'list'オプションに追従する "list"の 3 つのモードがあり、ウィンドウ毎に独立しています。
デフォルト値を変える場合は上記の通り g:zenspace#default_modeを設定してください。個別のウィンドウで変更したい場合は :ZenSpaceOn :ZenSpaceOff :ZenSpaceList を使用してください。

Q & A

Q. 色を変えたいんだけど?
A. 赤に変える例を載せておきます。

augroup vimrc-highlight
  autocmd!
  autocmdColorScheme * highlight ZenSpace ctermbg=Red guibg=Red
augroup END

Q. 普通のスペースとかは表示できないの?
A. 全角スペース専用です。通常のスペースやタブや行末スペースは、Vim標準の 'listchars'オプションを設定するといい感じに表示できるので、そっちを使うことをオススメします。

Q. Conceal とか使って□で表示できない?
A. 検討したんですが、Conceal の制限がキツすぎて見送りました。詳細はこちらを読んでください。


Enjoy!

vimproc に Windows の DLL ダウンロード機能を入れた

$
0
0

tl;dr

以下を vimrc の最初の方に書く。

letg:vimproc#download_windows_dll =1

本文

vimproc は外部プロセスを非同期実行するのに必要な Vimのライブラリ。これを利用しているプラグインも結構ある。
これはとても便利なのだけど、動的ライブラリを別途ビルドする必要がある。
LinuxMac OS Xなんかの環境では、標準でビルド環境が整備されているのもあり、ここで苦労することはあまりないと思う。しかし、Windowsだと標準ではビルド環境がないため、ビルドすること自体が難しい。
kaoriya 版の Vimに同梱されている vimproc には DLL も含まれているので、これを利用している人もいるのではないだろうか。
ただ、最新版が使いたかったり、複数 OS で同じ設定を使いたいという理由でプラグインマネージャで vimproc を管理したい人もいるだろう。私がそうだ。そういった場合、kaoriya 版のプラグインはちょっと使いづらい。
とりあえずビルドだけでもなんとかならないか、と思って以前やったのがこれ。

Add appveyor.yml to build DLL for MS Windows by thinca · Pull Request #217 · Shougo/vimproc.vim · GitHub

これによって、vimproc のバージョンが上がり、タグが打たれると、自動で DLL がビルドされて誰でもダウンロードできるようになった。ダウンロードは以下のページからできる。

https://github.com/Shougo/vimproc.vim/releases

というわけで自分でビルドしなくてもダウンロードして配置するだけ。便利。だったのだけど、正直ダウンロードしてくるのも面倒になった。プラグインマネージャで vimproc をインストールした直後は必ず「DLL がない」とエラーが出る。とてもつらい。
すでにビルド済みバイナリはネット上にあるわけなので、ダウンロードも自動でやってくれるとラクチン。というわけでそういう機能を作った。

Download windows dll automatically by thinca · Pull Request #242 · Shougo/vimproc.vim · GitHub

最初は全自動だったのだけど、デフォルトでダウンロードされるのは困る、という意見もあり、確かにアグレッシブすぎる感じがしたので、設定を足した。以下の設定を vimrc に書いておけば、DLL がない場合は vimproc がロードされるタイミングで自動でダウンロードされる*1。また、DLL が古かった場合は自動で更新してくれる(この場合は Vimの再起動が必要)。

letg:vimproc#download_windows_dll =1

この設定は vimproc が使用されるより前に書く必要があり、プラグインマネージャが vimproc を使う場合もあるため、できるだけ vimrc の先頭に書いた方が良い。
これでようやく vimproc の DLL との格闘に終止符を打てた気がする。
Vimには job という外部プロセスを非同期実行するための機能が入りつつあり、きちんと入って各プラグインがこちらを利用し始めたら vimproc 自体がオワコンになる可能性も 0 ではないが*2、今は気にしないでおこう…。

*1:ダウンロードも最初は curl必須だったのだけど、raa0121 さんの提案で powershellでもダウンロードするようにしたので大抵の環境でダウンロード可能になった。raa0121++

*2:vimproc には非同期実行以外にもいくつか機能があるのでそっちの用途で使われる可能性はありそう

はてなブログに移行した

$
0
0

現在手元の設定ファイル類を整理しており、どこかから拾ってきたようなファイルがいくらかあるので、それらを可能な限り排除しようとしていた。

その中にはてな記法Vim向けの syntax ファイルがあり、これは hatena.vimに含まれているのだが、投稿機能は必要なかったので syntax ファイルだけ持っていたようだ。

hatena.vimプラグインとして管理してしまうことも考えたが、そもそもはてなブログにしてしまえば markdown になるから hatena.vim必要なくなるのではってことで移行してみた。

以上。


Minecraft サーバ Spigot のプラグインを Kotlin で書いてみたときのメモ

$
0
0
  • 個人の作業メモになるので、内容の保証は一切できないけれど、誰かの参考になれば。
  • 各レイヤーで何をやっているか知りたかったので、低レベルなところをコマンドラインでやってみている。
  • 実際に開発する場合はもうちょっとちゃんと環境を整えた方が良いように思う。
  • 私自身そんなに詳しいわけではないので突っ込み歓迎。

環境

このメモの手順通りに作業した場合には以下のようなディレクトリ構造になる。

.
|- kotlin            (Kotlin コンパイラ)
|- kikori-plugin     (木こりプラグイン)
|- kotlin-plugin     (Kotlin サンプルプラグイン)
|- hello-plugin     (Pure Java サンプルプラグイン)
|- spigot           (Spigot 自体のビルド作業用)
`- spigot-server    (Spigot サーバを動かす用)

Spigot とは

https://www.spigotmc.org/

Minecraftのサーバ。プラグインを入れられる。Javaで動く。

Spigot の導入

大人の事情により Spigot はバイナリ配布されていない。代わりに簡単にビルドできるビルドツールがあるので、これでビルドする。

https://www.spigotmc.org/wiki/buildtools/

↑に各環境の詳細な手順が書かれているので、うまく行かない場合は読むとよい。

まずはビルドツールを取得する。

$ mkdir spigot
$ cd spigot
$ curl https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -o BuildTools.jar

そしてこれを使ってビルド。今回は 1.9 を使う。今のところ、指定なしだと 1.8 がビルドされる模様。

ちなみにビルドツールを動かすには、Javaの他に Git も必要。ない場合はインストールしておく。

$ java -jar BuildTools.jar --rev 1.9

めっちゃがんばってビルドしてくれる。しばし待つと、カレントディレクトリに spigot-1.9.jarができる。これがサーバになる。

実際に起動してみる

https://www.spigotmc.org/wiki/spigot-installation/

まずはプラグインなしでとりあえず動かしてみる。実行は spigot-1.9.jarだけがあればできる。

こいつは起動時にカレントディレクトリにあれこれファイルやディレクトリを生成するので、新しいディレクトリで作業するのがよい。

$ mkdir ../spigot-server
$ cp spigot-1.9.jar ../spigot-server
$ cd ../spigot-server

引数が長いので、簡単に起動用のシェルスクリプトを作っておくと便利。

$ echo 'java -Xms512M -Xmx1024M -XX:MaxPermSize=128M -jar spigot-1.9.jar' > start.sh
$ chmod +x start.sh

起動する。

$ ./start.sh
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
Loading libraries, please wait...
[19:04:47 INFO]: Starting minecraft server version 1.9
[19:04:48 INFO]: Loading properties
[19:04:48 WARN]: server.properties does not exist
[19:04:48 INFO]: Generating new properties file
[19:04:48 WARN]: Failed to load eula.txt
[19:04:48 INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
[19:04:48 INFO]: Stopping server
>

$ ls
eula.txt  logs/  server.properties  spigot-1.9.jar

$

初回は起動に失敗する。使用許諾契約に同意する必要がある。eula.txtというファイルが生成されているので、これを Vimなどの適当なエディタで開く。

#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).
#Sun Mar 13 19:04:48 JST 2016
eula=false

EULAの URL があるので開いて目を通し、問題がなければ eula=falseeula=trueに書き換えて保存。再び起動する。

$ ./start.sh
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
Loading libraries, please wait...
[21:22:23 INFO]: Starting minecraft server version 1.9
[21:22:23 INFO]: Loading properties
[21:22:23 INFO]: Default game type: SURVIVAL
[21:22:24 INFO]: This server is running CraftBukkit version git-Spigot-6f291ea-55a8535 (MC: 1.9) (Implementing API version 1.9-R0.1-SNAPSHOT)
[21:22:24 INFO]: Unable to find file banned-players.json, creating it.
[21:22:24 INFO]: Unable to find file banned-ips.json, creating it.
[21:22:24 INFO]: Unable to find file ops.json, creating it.
[21:22:24 INFO]: Unable to find file whitelist.json, creating it.

...(中略)...

[21:23:31 INFO]: Preparing start region for level 2 (Seed: 5519750147800174725)
[21:23:32 INFO]: Preparing spawn area: 11%
[21:23:33 INFO]: Preparing spawn area: 25%
[21:23:34 INFO]: Preparing spawn area: 39%
[21:23:35 INFO]: Preparing spawn area: 51%
[21:23:36 INFO]: Preparing spawn area: 62%
[21:23:37 INFO]: Preparing spawn area: 75%
[21:23:38 INFO]: Preparing spawn area: 90%
[21:23:39 INFO]: Done (73.641s)! For help, type "help" or "?"
>

無事起動した。最後の >はプロンプトで、管理用のコマンドなどが実行できる。

この状態で Minecraft 1.9 のクライアントから Multiplayer でサーバに接続すれば、ゲームが遊べる。サーバとクライアントが同じマシンなら、接続先のサーバアドレスに localhostと入力して接続すれば OK。

サーバを終了させるには stopコマンドを実行すればよい。

Pure Javaプラグインを作ってみる

Kotlin に入る前に、まずは Pure Javaプラグインを作ってみる。改めて断っておくと、とりあえず動くことを確認するための作業なので、構成はものすごく適当。

まずはプラグインのプロジェクト用にディレクトリを作る。

$ mkdir ../hello-plugin
$ cd ../hello-plugin

プラグインをビルドするには、Spigot のライブラリが必要になる。最初にビルドした中にあるので、コピーしてくる。

$ cp ../spigot/Spigot/Spigot-API/target/spigot-api-1.9-R0.1-SNAPSHOT.jar spigot-api.jar

HelloPlugin.javaとして、以下のようなファイルを作る。

import org.bukkit.plugin.java.JavaPlugin;

publicclass HelloPlugin extends JavaPlugin {
  @Overridepublicvoid onEnable() {
    getLogger().info("Hello, world!");
  }
}

プラグインがロードされた際に、ログに Hello, world!と表示するだけのプラグインだ。

これをコンパイルする。

$ javac -cp spigot-api.jar HelloPlugin.java

次に、プラグインの構成情報のためのファイル、plugin.ymlを作成する。プラグインにはこれが必要になる。

# プラグイン名name: hello
# プラグインのメインクラス。パッケージ付きのフルネームを書くmain: HelloPlugin
# プラグインのバージョンversion:1.0

ここまででファイルは以下のような感じ。

.
|- HelloPlugin.class
|- HelloPlugin.java
|- hello.jar
|- plugin.yml
`- spigot-api.jar

プラグインに必要な plugin.ymlHelloPlugin.classを jar で固めて、サーバの pluginsディレクトリに放り込む。

$ jar cf hello.jar HelloPlugin.class plugin.yml
$ cp hello.jar ../spigot-server/plugins

あとはサーバを起動すれば、プラグインが読み込まれる。

$ cd ../spigot-server
$ ./start.sh
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
Loading libraries, please wait...
[22:18:07 INFO]: Starting minecraft server version 1.9
[22:18:07 INFO]: Loading properties
[22:18:07 INFO]: Default game type: SURVIVAL
[22:18:08 INFO]: This server is running CraftBukkit version git-Spigot-6f291ea-55a8535 (MC: 1.9) (Implementing API version 1.9-R0.1-SNAPSHOT)
[22:18:08 INFO]: Server Ping Player Sample Count: 12
[22:18:08 INFO]: Using 4 threads for Netty based IO
[22:18:08 INFO]: Debug logging is disabled
[22:18:08 INFO]: Generating keypair
[22:18:09 INFO]: Starting Minecraft server on *:25565
[22:18:09 INFO]: Using epoll channel type
[22:18:09 INFO]: Set PluginClassLoader as parallel capable
[22:18:09 INFO]: [hello] Loading hello v1.0
[22:18:09 INFO]: **** Beginning UUID conversion, this may take A LONG time ****

...(中略)...

[22:10:53 INFO]: Preparing spawn area: 66%
[22:10:53 INFO]: Preparing start region for level 2 (Seed: 5519750147800174725)
[22:10:54 INFO]: [hello] Enabling hello v1.0
[22:10:54 INFO]: [hello] Hello, world!
[22:10:54 INFO]: Server permissions file permissions.yml is empty, ignoring it
[22:10:54 INFO]: Done (9.339s)! For help, type "help" or "?"
>

ログに Hello, world!と表示されている。[hello]プラグイン名だ。

Kotlin とは

https://kotlinlang.org/

JVMで動く実用的な言語。Androidとかで動かすことも考えて作られてる。 先月の 2/15 に待望のバージョン 1.0 がリリースされた。

まとめると、私もよくわかってない。わかってないので今回触ってみることにした感じ。

インストール

今回はコマンドラインで動くコンパイラを入れる。

$ cd ..
$ curl -sL https://github.com/JetBrains/kotlin/releases/download/build-1.0.0/kotlin-compiler-1.0.0.zip -o kotlin-compiler-1.0.0.zip
$ unzip -q kotlin-compiler-1.0.0.zip
$ PATH=$PATH:$PWD/kotlinc/bin

$PATHはとりあえず設定したけど、必要なら .bachrcなどできちんと設定すること。

Kotlin でプラグインを作ってみる

Kotlin もインストールできたので、プラグインを作ってみる。まずはディレクトリの作成。

$ mkdir ../kotlin-plugin
$ cd ../kotlin-plugin

ライブラリと plugin.ymlも先に用意しちゃう。

$ cp ../spigot/Spigot/Spigot-API/target/spigot-api-1.9-R0.1-SNAPSHOT.jar spigot-api.jar
name: kotlin
main: KotlinPlugin
version:1.0

そして Kotlin のソースコードkotlin.ktを作る。

import org.bukkit.plugin.java.JavaPlugin

class KotlinPlugin : JavaPlugin() {
    override fun onEnable() {
        getLogger().info("Hello, Kotlin!")
    }
}

コンパイルする。

$ kotlinc -cp spigot-api.jar kotlin.kt -include-runtime -d kotlin.jar

-include-runtimeは、Kotlin のランタイムを jar に同梱して standalone にするためのオプション。実を言うと現段階のコードでは Kotlin のランタイムに依存していないので、これがなくても動くのだけど、書いていったらどうせ依存すると思うので今から入れておく。

さて、jar はできたけど、これには plugin.ymlが含まれていないので入れる。

$ jar uf kotlin.jar plugin.yml

そしてサーバの pluginsへ放り込んで動作確認。

$ cp kotlin.jar ../spigot-server/plugins
$ cd ../spigot-server
$ ./start.sh
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
Loading libraries, please wait...
[05:24:36 INFO]: Starting minecraft server version 1.9
[05:24:36 INFO]: Loading properties
[05:24:36 INFO]: Default game type: SURVIVAL
[05:24:37 INFO]: This server is running CraftBukkit version git-Spigot-6f291ea-55a8535 (MC: 1.9) (Implementing API version 1.9-R0.1-SNAPSHOT)
[05:24:37 INFO]: Server Ping Player Sample Count: 12
[05:24:37 INFO]: Using 4 threads for Netty based IO
[05:24:37 INFO]: Debug logging is disabled
[05:24:37 INFO]: Generating keypair
[05:24:37 INFO]: Starting Minecraft server on *:25565
[05:24:37 INFO]: Using epoll channel type
[05:24:37 INFO]: Set PluginClassLoader as parallel capable
[05:24:38 INFO]: [kotlin] Loading kotlin v1.0
[05:24:38 INFO]: [hello] Loading hello v1.0
[05:24:38 INFO]: **** Beginning UUID conversion, this may take A LONG time ****

...(中略)...

[05:24:46 INFO]: Preparing spawn area: 68%
[05:24:47 INFO]: Preparing start region for level 2 (Seed: 5519750147800174725)
[05:24:48 INFO]: [kotlin] Enabling kotlin v1.0
[05:24:48 INFO]: [kotlin] Hello, Kotlin!
[05:24:48 INFO]: [hello] Enabling hello v1.0
[05:24:48 INFO]: [hello] Hello, world!
[05:24:48 INFO]: Server permissions file permissions.yml is empty, ignoring it
[05:24:48 INFO]: Done (10.087s)! For help, type "help" or "?"
>

ちゃんと動いてる。

もうちょっと実践的なやつを作ってみる

せっかくなので何か簡単に作ろうと思う。というわけで、木を破壊したらその木より上にある木も全部破壊してくれる、いわゆる木こり機能を作ってみる。

コードは Gist に貼っておく。以下。Kotlin のコードをまともに書いたのは今回が初めてなので、Kotlin らしくなっていいるかはわからない。良ければアドバイスください(Gistにコメントなど歓迎)。

kikori mod for Spigot by Kotlin

Spigot では様々なイベントに対して処理を行える。Listenerインターフェースを実装したクラスで @EventHandlerアノテーションをつけたメソッドを定義し、そこでイベントを受け取る。引数のイベントの型で受け取れるイベントが決まり、イベントのオブジェクトからイベントに関する情報が取れる。今回使った BlockBreakEventなら、壊れたブロックや壊したプレイヤーの情報が取得できる。あとはこのクラスをプラグインマネージャに登録すればよい。

今まで通りビルドすれば動かせる。

$ kotlinc -cp spigot-api.jar kikori.kt -include-runtime -d kikori.jar
$ jar uf kikori.jar plugin.yml
$ cp kikori.jar ../spigot-server/plugins

結果は自分の手でご確認ください。(動画とか用意するの面倒)

参考リンク

カラースキームに個人的に求めるもの

$
0
0

最近 Vimのカラースキームの自作に関する記事をちらほら見かける。

私自身も最近、いいカラースキームないかなーと探していたりするので(作る気は皆無)、私が探す際のポイントなんかを書いておく。

ちなみにこの記事では主にカラースキームの機能面についてのみ言及する。 配色に関しては私はセンスがほぼないので、色について完全に感覚で選んでいて参考にならない。

一通りの色が定義してある

最重要項目なのだけど、できていないものが多い。個人的には全て設定されていてほしい。 大きく分けて Vim自身が使う部品のハイライトと、テキスト内の構文ハイライトで使うものがある。

前者の一覧は :help highlight-groupsで見ることができる。この記事を書いている時点での最新版である Vim 7.4.1639 では以下の 45 個だ。たまーに本体への機能追加で増えるので、注意したい。

*hl-ColorColumn*
ColorColumn     'colorcolumn'で設定された列の表示に使われる
*hl-Conceal*
Conceal         Conceal されたテキストの代わりに表示される代替文字の表示に使わ
                れる ('conceallevel'参照)
*hl-Cursor*
Cursor          カーソル下の文字
*hl-CursorIM*
CursorIM        Cursorと同じだが、IMEモードにいるとき使われる|CursorIM|。
*hl-CursorColumn*
CursorColumn    'cursorcolumn'がオンになっているときのカーソルがある画面上の桁
*hl-CursorLine*
CursorLine      'cursorline'がオンになっているときのカーソルがある画面上の行
*hl-Directory*
Directory       ディレクトリ名(とリストにある特別な名前)
*hl-DiffAdd*
DiffAdd         差分モード: 追加された行 |diff.txt|
*hl-DiffChange*
DiffChange      差分モード: 変更された行 |diff.txt|
*hl-DiffDelete*
DiffDelete      差分モード: 削除された行 |diff.txt|
*hl-DiffText*
DiffText        差分モード: 変更された行中の変更されたテキスト |diff.txt|
*hl-ErrorMsg*
ErrorMsg        コマンドラインに現れるエラーメッセージ
*hl-VertSplit*
VertSplit       垂直分割したウィンドウの区切りとなる桁
*hl-Folded*
Folded          閉じた折り畳みの行
*hl-FoldColumn*
FoldColumn      'foldcolumn'*hl-SignColumn*
SignColumn      目印|signs|が表示される行。
*hl-IncSearch*
IncSearch       'incsearch'のハイライト; ":s///c" で置換されたテキストにも使
                われる。
*hl-LineNr*
LineNr          ":number" と ":#" コマンドの行番号。'number'オプションか
                'relativenumber'オプションが設定されているときにはその表示に
                も使われる。
*hl-CursorLineNr*
CursorLineNr    LineNr と同じだが 'cursorline''relativenumber'が設定され
                ているときに現在行に使われる。
*hl-MatchParen*
MatchParen      カーソル下の文字、または直後の文字が括弧であるとき、その文字と
                対応する括弧に使われる。|pi_paren.txt|

*hl-ModeMsg*
ModeMsg         'showmode'のメッセージ (例. "-- INSERT --")
*hl-MoreMsg*
MoreMsg         |more-prompt|
*hl-NonText*
NonText         ウィンドウの端の '~'と '@'、'showbreak'で設定された文字など、
                実際のテキストには存在しない文字(例. 全角文字が行末に収まらな
                いとき ">" が表示される)。
*hl-Normal*
Normal          通常のテキスト
*hl-Pmenu*
Pmenu           ポップアップメニュー: 通常の項目。
*hl-PmenuSel*
PmenuSel        ポップアップメニュー: 選択されている項目。
*hl-PmenuSbar*
PmenuSbar       ポップアップメニュー: スクロールバー。
*hl-PmenuThumb*
PmenuThumb      ポップアップメニュー: スクロールバーのつまみ部分。
*hl-Question*
Question        ヒットエンタープロンプト|hit-enter|とyes/noクエスチョン
*hl-Search*
Search          最後に検索した語のハイライト('hlsearch')を参照。
                quickfixウィンドウ内の現在行のハイライトや、それに類するものに
                使われる。
*hl-SpecialKey*
SpecialKey      ":map" でリストされるメタキーと特別なキー。テキスト中の
                unprintableな文字を表示するのにも使われる。
                一般に: 実際とは異なる文字で表示されるテキスト
*hl-SpellBad*
SpellBad        スペルチェッカに認識されない単語。|spell|
                これは他のハイライトと同時に組み合わせられる。
*hl-SpellCap*
SpellCap        大文字で始まるべき単語。 |spell|
                これは他のハイライトと同時に組み合わせられる。
*hl-SpellLocal*
SpellLocal      スペルチェッカによって他の地域で使われると判断される単語。
                |spell|これは他のハイライトと同時に組み合わせられる。
*hl-SpellRare*
SpellRare       スペルチェッカによってまず使わないと判断される単語。|spell|
                これは他のハイライトと同時に組み合わせられる。
*hl-StatusLine*
StatusLine      カレントウィンドウのステータスライン
*hl-StatusLineNC*
StatusLineNC    非カレントウィンドウのステータスライン。
                Note: これが "StatusLine" に等しい場合、カレントウィンドウのス
                テータスラインに "^^^" が使われる。
*hl-TabLine*
TabLine         タブページの行の、アクティブでないタブページのラベル
*hl-TabLineFill*
TabLineFill     タブページの行の、ラベルがない部分
*hl-TabLineSel*
TabLineSel      タブページの行の、アクティブなタブページのラベル
*hl-Title*
Title           ":set all"、":autocmd" などによる出力のタイトル。
*hl-Visual*
Visual          ビジュアルモード選択
*hl-VisualNOS*
VisualNOS       vimが "Not Owning the Selection" のときのビジュアルモード選択。
                これをサポートしているのはX11GUI|gui-x11|と|xterm-clipboard|の
                み。
*hl-WarningMsg*
WarningMsg      警告メッセージ
*hl-WildMenu*
WildMenu        'wildmenu'補完における現在の候補

後者の、構文ハイライトに使われるもののリストは、:help group-nameで確認できる。

*Comment        o コメント

*Constant       o 定数
         String         o 文字列定数: "これは文字列です"
         Character      o 文字定数: 'c', '\n'
         Number         o 数値定数: 234, 0xff
         Boolean        o ブール値の定数: TRUE, false
         Float          o 不動小数点数の定数: 2.3e10

*Identifier     o 変数名
         Function       o 関数名(クラスメソッドを含む)

*Statement      o 命令文
         Conditional    o if, then, else, endif, switch, その他
         Repeat         o for, do, while, その他
         Label          o case, default, その他
         Operator       o "sizeof", "+", "*", その他
         Keyword        o その他のキーワード
         Exception      o try, catch, throw

*PreProc        o 一般的なプリプロセッサー命令
         Include        o #include プリプロセッサー
         Define         o #define プリプロセッサー
         Macro          o Defineと同値
         PreCondit      o プリプロセッサーの #if, #else, #endif, その他

*Type           o int, long, char, その他
         StorageClass   o static, register, volatile, その他
         Structure      o struct, union, enum, その他
         Typedef        o typedef宣言

*Special        o 特殊なシンボル
         SpecialChar    o 特殊な文字定数
         Tag            o この上で CTRL-]を使うことができる
         Delimiter      o 注意が必要な文字
         SpecialComment o コメント内の特記事項
         Debug          o デバッグ命令

*Underlined     o 目立つ文章, HTMLリンク

*Ignore         o (見た目上)空白, 不可視  |hl-Ignore|

*Error          o エラーなど、なんらかの誤った構造

*Todo           o 特別な注意が必要なもの; 大抵はTODO FIXME XXXなど
                          のキーワード

こちらは、先頭に *が付いているものだけ定義されていればよい。それ以外のものはデフォルトで同じグループの *付きのものにリンクされているので、同じ色で表示される。

CUI/GUI対応

私は VimCUIでも GUIでも使うので、両対応のものが欲しい。両者でほぼ同じ見た目だと嬉しい。

実は CSApprox.vimというプラグインを使うと任意の GUI向けカラースキームを CUI向けに変換することができるのだけど…変換したファイルの管理などを考えると面倒なのであまりやりたくない。最初から対応していてくれると嬉しい。

background=dark

そろそろ完全に個人の好みの領域に入ってきました。黒背景が好きです。

単色系より色んな色が使われているやつ

単色系のはスタイリッシュではあると思うけども、せっかく色がついてるのに見分けづらかったりして実用性に疑問があるので。はい。個人的な好みになります。

VertSplit は文字が見えないやつ

完全に指定が細かくなってきた。ウィンドウの垂直分割(左右に分ける)の縦区切りの線、あれ |が使われているのだけど、背景色と前景色を同じにして見えなくなってるほうが好き。

すごく細かいところを挙げるとまだある気がするけどこの辺にしておこう。

以上

なにかオススメあったら教えてください。

参考

カラースキームを作ってみよう - 永遠に未完成

Software Desing 2016年5月号の Vim 特集記事に寄稿しました

$
0
0

技術評論社から発売される Software Design 2016年5月号の第1特集「Vim[実践]投入」に寄稿しました。

gihyo.jp

全5章の構成で、5人の Vimmerが1人1章を担当する豪華な内容になっています。

書いたこと

私は第2章「Vimだからできる、一歩先行く編集術」を担当しました。

今回の特集は、4月から新社会人になった方々をメインターゲットに、入門者向けの内容になっています。 その中でも第2章では、Vimならではの機能について紹介しました。

この記事を見て、多くあるエディタの中から Vimを選ぶ意義について感じてもらえれば幸いです。

書けなかったこと

今回、これから Vimを使い始める人達を対象に記事を書くということで、help の引き方についての解説を入れたかったのですが、紙面の都合上叶いませんでした。

Vimを使っていくにあたって、help を引くことはとても重要です。Vimは設計上の目標(:help design-goals)の一つによくドキュメント化されていることを挙げており、大抵のことは help に書いてあります。また、プラグインについても、まともなプラグインであればドキュメントが書かれていて、Vimの中からいつでも参照できるようになっています。

調べ方を知っておくというのは Vimに限らず重要なことです。記事内での解説は叶いませんでしたが、もし Vimを使うことに決めた場合は、まずはヘルプのヘルプ(:help helphelp)などを見て引き方を知っておくとよいでしょう。

それでは、よい Vimライフを!

はてなダイアリーからはてなブログへ移行する際の注意点

$
0
0

先日、はてなダイアリーからはてなブログへ移行した。

thinca.hatenablog.com

移行に際して問題があったので書き記しておく。

TL;DR

はてなダイアリー<hoge>って書いてたら、はてなブログに移行すると死ぬ。

あらすじ

私は今まではてなダイアリーでそれなりに記事を公開していた。Vim中でも記事が多く、<Leader>のようなキーの記法をあちこちで多様していた。 はてなダイアリーでは html タグは一部のタグしか使えない仕様だったため、それ以外の <Leader>のようなタグっぽい文字列はそのまま表示されていたので、なんの問題もなかった。

はてなブログでは、はてなダイアリーで使えた「はてな記法」と Markdown の両方が選択できるようになっており、はてなダイアリーで書いた記事は「はてな記法」で書かれた記事として公開されるので、そのまま移行できるとの話だったので、はてなブログへの移行を行った。

ところが、はてなブログに移行後しばらくして気付いたのだが、この <Leader>のような文字列が、はてなブログの記事内では表示されなくなってしまっていた。

ゆるせなかったのでサポートにメールし、調査を行ってもらったのだけど、最終的に以下のような返事が返ってきた(本文のみ抜粋)。

いつもはてなをご利用いただきありがとうございます。

返信が遅くなりまして申し訳ございませんでした。

はてなダイアリーでは特定のタグしか書けない仕様となっているため、 「<」 や 「>」をそのまま表示させることができましたが、 はてなブログでは、任意のタグを書ける仕様となっているため、 実体参照表記でないと表示がされません。

インポート時に一括置換できないか検討いたしましたが、今回は見送ることになりました。 大変お手数をおかけ致しますが、記事の編集画面を開いていただき、 手作業で置換をしていただくようお願い致します。

【置換例】 <Leader> → &lt;Leader&gt;

どうぞよろしくお願いいたします。

どうやらはてなダイアリーでの「はてな記法」と、はてなブログでの「はてな記法」には厳密には互換性はないらしい。

改めて移行に関するヘルプページを確認すると、以下のような説明が足されていた。

  • HTMLタグの扱いの違いに注意してください。はてなブログでは、はてなダイアリーと違ってHTMLタグがすべて利用できるため、<と>で囲まれた任意の文字列をHTMLタグとして解釈します

※はてなブログで、<と>で囲まれた任意の文字列を表示するには、たとえば&lt;foo&gt;のように実体参照で表記してください。

先月の時点の同ページにはこの記述はないため、恐らく私の問い合わせを契機に追記されたのだと思う。

返事に1ヶ月半ほどかかっているところを見ると、それなりに検討した結果だと思うので、残念だけども仕方ない。

というわけで、これから移行を考えている人は注意してください。 また、私の古い記事の中にはこれらの理由により一部文字が消えている可能性があるので、ご了承頂きたい。さすがに過去の記事全てをチェックするのはしんどすぎる。もし発見された方は報告してもらえれば可能な限り直そうと思います。

Vim で help が引ける npm パッケージを作った

$
0
0

色々あって node.js から Vimの help を引く必要が出てきたので、npm パッケージにしてみた。人生初 npm パッケージです。

https://www.npmjs.com/package/vimhelp
https://github.com/thinca/node-vimhelp

特に必然性はなかったのだけど、せっかくなので勉強も兼ねて ES2015 で書いてみた。node.js にも依存しているので、node.js 6 以降が必須です。 このパッケージは外部プロセスとして Vimを起動して、help を引きます。なので環境に Vimが必要です。また、プラグインの help も引きたいというそれだけのために Git を使った簡易プラグインマネージャも付いてます。こちらを使う場合は Git が必要。 使い方とかは README を参照してください。

苦労した点

初めての npm

今回初めてだったので、npm の作法やら ES2015 の機能やら、ついでにテストやらカバレッジ計測やら色々調べながらやった結果、必要以上に時間がかかってしまった…。

非同期地獄

node.js の非同期 APIは、呼び出しスタックの奥底に 1 つでも非同期が混じると根本から非同期の APIにする必要が出てくるのがだいぶしんどく感じた。Promise のおかげでネスト深いは回避できているものの、やはりまだしんどい印象が拭えない。ES2016 で入るとの噂の await があるとここがかなりマシになりそうな予感がするので、はよ。

外部プロセスのテスト

外部プロセスを起動するようなプログラムのテストはどこまでモックにするべきかがかなり悩ましい。コマンド実行部分をモックにすると、想定したコマンドが実行されているかまではテストできるが、想定したコマンドが期待した結果を生むかまではテストできない。そこまですべきなのかどうなのか…。 今はモック化するのが難しかったという理由もあって、テストでも実際にコマンドが実行されている。なのでプラグインマネージャのテストが走る度に git cloneが実行されるという感じに…。実行も遅くなるので正直しんどい。

機能実現のアプローチについて

今回 Vimの help を引くという機能を実現するにあたって、Vimを実際に実行するという手段を選んだわけだけど、helptags や help ファイルを直接読んでパースするという手段も考えられた。 実際のところ、直接読んだ方が速度や効率は良いと思う。ただ、tags ファイルをパースしたり、Vimがやっている :helpの引数の独自解釈などを自分でやるのが面倒だったため、今回は直接起動する方法を取った。こちらの方法だと、今後 Vimが :help の動作を拡張などした場合にも対応できる。そういう機会はそうそうないとは思うけども。少なくとも私が必要としている用途においてはこれでも十分な速度で動いている。

さいごに

初 npm パッケージ、作ってみたのはいいけど自分以外には需要なさそう。まだ欲しい機能がいくつかあるので、のんびり更新していく予定。

Viewing all 102 articles
Browse latest View live