生涯未熟

プログラミングをちょこちょこと。

.zsh_historyにおける非ASCII文字の扱いについて

この3連休、夢中でコーディングしてあるツールを作っている最中、.zsh_historyの特異な挙動を発見しましたので書き残しておきます。

一体何が起こったのか?

Goでツールを作っていたのですが、.zsh_historyを読み込んでファイル内容を出力したところ以下のようになりました。

思いっきり文字化けしている・・・
見るに、日本語が文字化けしている様子。

で、あれー?と思ったので.zsh_historyvimで開いてみました。

???🤔

.zsh_historyの特異な性質を知る

さて、なんでこのように日本語が記述されていないのでしょうか?
調べたところ以下のブログ記事に辿り着きました。

kawabata.github.io

ここに興味深い文言が。

zshのヒストリファイルは、保存するデータの各バイトにおいて、それが 0x80-0x9d または 0xa0 のとき、その前に 0x83 を入れて、続くバイトの 6bit 目を反転させるようになっている。

ほほう?🤔

これがどういうことか、具体的な例を使って見ていきましょう。
例として「あいうえお」という文字列を使います。

この「あいうえお」を.zsh_historyで見ると以下のようになります。

ã<81><82>ã<81><83>¤ã<81><83>¦ã<81><83>¨ã<81><83>ª

.zsh_historyはlatin1(ISO/IEC 8859-1)という形式になりますので、その文字コード表を元にすると以下のように16進数に直すことが出来ます。
(分かりやすいように適宜スペースを挿入しています)

E38182 E38183 A4 E38183 A6 E38183 A8 E38183 AA

ここで、 0x80-0x9d または 0xa0 のとき、その前に 0x83 を入れて というのを考えると、上記の 83 に当たる所が該当します。
今回だと、該当するのは A4 , A6 , A8 , AA ですね。

なので、 続くバイトの 6bit 目を反転させるようになっている というルールに従って、6bit目を更に反転させると、
84 , 86 , 88 , 8A になります。

で、このルールに従って書き直すと以下のようになります。

E38182 E38183 84 E38183 86 E38183 88 E38183 8A

そして、更にマーキングに使っている 83 を削除すると

E38182 E38184 E38186 E38188 E3818A

といった形になります。

これを、Unicode文字コード表に照らし合わせると、あら不思議。

あいうえお

と読み解くことが出来ます。

Goだとどうする?

さて、ここまで理解した上で、Goだと以下のようにParse処理を書くことが出来ます。

これに scanner.Scan 等で取得してきた文字列を突っ込むことで、見事に日本語に変換してくれます。

.zsh_historyの特異な性質を知ることが出来、また一つ学びになりました。
何故にこのような処理を非ASCII文字に対して行っているのかは謎なところですが・・・🤔

優秀なプログラマになるには

コード書け!!!!!!!!!!!!!!!!!!!!!!

fsnotifyは何故Vimで動かないのか?

という掲題ですが、まさにハマったことなのでメモ代わりに記事として書いておきます。

一体何が?

Goでファイル監視をしようと思いライブラリを探した結果、fsnotifyというライブラリを発見しました。

github.com

「Star数も多いし、こりゃいいや。使っちゃれ。」と思い、使ってみたところ何故かファイル変更が監視できていませんでした。
ここから色々と探る旅が始まりました。

尚、今回環境としてはOS X + Gogland + IdeaVimになります。

まずはライブラリを読んでみる

fsnotifyは以下のように使っていました。

で、このコードからライブラリの中身を探索することに。

最初に使っているfsnotifyの要素としては NewWatcher です。
試しにこの処理を追いかけてみましょう。

ふむふむ、ここで出てきている kqueue というのが謎だったので、調べてみる。

kqueue - Wikipedia

なーるほど、BSD系のファイル監視ツールなのですね。
OS XFreeBSDをベースとしているので、勿論このkqueueが使えます。
ということは、このfsnotifyはOSによってファイル監視ツールを使い分けていて、今回の場合 kqueue を使っているということですね。

さて、ここまで来たら次に気になるのは「kqueueでファイル監視してみて再現するのか?」ということでした。

kqueueを使ってみる

では、kqueueを使ってファイル監視してみましょう。

Goだとこんな感じで、kqueueを使ったファイル監視が実現できます。

これを実行してみた結果・・・ダメでした(´・ω・`)

今回の件はfsnotifyの実装が悪いということではないことが分かりました。
ということは、残りの可能性としてはVimが悪いということか・・・?

Vim以外のエディタで試してみる

fsnotifyでファイル監視し、ファイルを別のエディタで編集してみました。(使用エディタはMacのテキストエディット)
結論から言うと、ちゃんとファイル監視出来ていました

Vim、お前だったのか・・・

では、何故Vimだとダメだったのでしょう?
今度はそれを探りに行きます。

kqueue ✕ Vim = ダメ?

まず手始めにfsnotifyのIssueを探し回りました。
そこで発見したのは以下のようなIssueでした。

github.com

要約してみると、

質問者「Vim使った場合にのみ、ファイル編集後にイベントをキャッチしてくれなくなりました」
OSSオーナー「どうもVimのAtomic Saveの仕組みのせいだと思うよ」

なーるーほーどー。
このAtomic Saveってなんじゃらほい?と思い、これまた調べてみることに。

調べてみるとこのAtomic SaveはVimがファイル編集中に退避ファイル(.swpか~)を吐き出し、その後保存する機構のようです。
そういえば確かに、Vimでの編集中に.swpっての吐いてました。 保存までの流れをdtrussで詳しく追いかけた記事がありましたので、詳しく知りたい方は以下のご一読を。

Vim system calls when saving a file · GitHub

この仕組みがどうもkqueueによるファイル監視ができない原因の模様。

更なる調査

「んじゃどうすっかな・・・?」と調査を続けていると、Redditにこんな記事を見つけました。

www.reddit.com

これはまさに掲題の件を話しているスレッドになるのですが、その中で
「The best work around right now is to watch the directory containing test.txt instead.
(今のところ最善の方法は、代わりにtest.txtを含むディレクトリを見ることです)」

という文言を発見。

なるほど!監視対象をディレクトリにするのはまだ試していなかった!!と思い、すぐさま試してみることに。

おっ、これだとVimで編集しても無事にイベントをキャッチすることができました!
ただ、 ./test/*.go のようなワイルドカードを使った指定がfsnotifyでは出来なかったり、 ./test/test1 のような階層構造になったディレクトリを監視対象としてくだないようなので(これはkqueueの制限)色々と使い勝手が難しいですね:-(

OS Xのみになるのですが、FSEventsという仕組みがあってこちらを使うとディレクトリの階層構造を探索して、監視対象にはしてくれるみたいです。
一応fsnotify内で実装はされているようです、気になる方は見てみてください。

github.com

まとめ

  • fsnotifyを使う時はなるべくディレクトリを監視対象にしよう
  • kqueueには色々と制限があるのでMacのみに対応する場合はFSEventsを使うのもアリ

色々と探ってみた結果、得るものが多くて良かったです:-)

[追記] 「node.jsとかgulpとかでファイル単位での監視って出来たような・・・🤔」とか思って確かめてみましたがダメでした・・・
やはりkqueueの仕組みを使ってる模様。当たり前か。

OSS builderという話をしました

ltlovers.connpass.com

というイベントで「OSS builder」という話をしてきました。

どういう内容か

大体の骨子はスライドに書いてある通りなのですが、OSS活動する中で学んだことを文字に起こしてみました。 特に以下の3つは一番聴いていただいた方に伝えたかったことです。

  • 自分が一番のユーザー
  • OSSは盆栽
  • とりあえず理論

自分が一番のユーザー

自分が欲しいモノを作り、自分の作ったモノに対して一ユーザーとして使い倒すことが、楽しくOSS活動を続けるコツだと思います。
結局、「ぼくが かんがえた さいきょうの ◯◯」を想像し、作っている時が一番楽しいんだなと。

OSSは盆栽

昔、バイト先の長老が「盆栽は究極の育成ゲー」と仰っていて、それがOSSにも繋がるものがあるんじゃないかな、と。
盆栽は何年もかけてコツコツと毎日世話をし、最終的に風光明媚な芸術品として仕上げます。
OSSもコツコツとコミットし、理想とする形に近づけていく作業なので、ほぼ一緒なものです。

また、盆栽の初め方として「実生」「挿し木」「接ぎ木」「取り木」の4つがあります。
実生は「種を撒いて育てる方法」、挿し木は「育っている盆栽の枝を切り取り、土に挿して育てる方法」、
接ぎ木は「台木に対して別の特性を持つ木を刺し込み育てる方法」、取り木は「枝から樹皮を剥がし、そこで根を張らせてから植え替え育てる方法
これらはOSS活動において以下に当てはまるんじゃないかと思ってます。

  • 実生:0からコードを書いていく
  • 挿し木:既にあるコードを参考にし、新たに作っていく
  • 接ぎ木:他のOSSに対してコントリビュートする
  • 取り木:他のOSSを新たに自分がオーナーとなり、作っていく

なので、僕はOSS=盆栽説を唱えていきたい。

とりあえず理論

OSSにおいて「とりあえず」って言葉を使っていけばすんなりモノが出来るんじゃないかなーと雑に思ってます。

  • 何か閃いたら「とりあえず」リポジトリを作る
  • 空でもいいので「とりあえず」READMEを作る
  • サンプルコードレベルでも「とりあえず」書いてみる
  • 暇な時に「とりあえず」コードをいじってみる
  • 「とりあえず」やってたらいつの間に完成

昔読んだ物の本で「とりあえず15分何かを始めてみると、そこから1時間くらい継続出来る。とりあえずやってみることが重要。」と書いてあり、実際試してみると意外と15分の壁を過ぎた辺りで集中力が形成されるのを感じました。
この「とりあえず何かを始めてみる」ことの重要性が、今回のとりあえず理論に繋がっています。

かるーい気持ちで「とりあえずやってみっかー」ってなることが大事ですね。

結局こういうことを伝えたかった

OSSを作ることによってプログラミングで何かを生み出す楽しさを、もう一度再燃して欲しいという想いを密かに込めて発表しました。
初めてプログラミングを学んだ時には、きっとHello, World!を出すだけでもテンションが上ったと思うんです。
こういう小さな高揚が、エンジニアとしての生活が長くなり、慣れてくるにつれて薄まってくる人も中にはいるはずです。
そういう方こそOSS活動を始めて、またこういう楽しさを思い出して欲しいな、と。

まとめ

「こんなこと言っちゃってお前何様だよ」とか思われるかもしれませんが、まだまだしょうもないエンジニアです、はい。
ただ、しょうもないながらも細々とやってきて得た実感なので、こういうことを思ってる人もいるんだなーくらいに読んで頂けたら幸いです。

wikipediaの寄付のお願いを非表示にするchrome拡張

作りました👌

chrome.google.com

実装はめっちゃ簡単でdisplay: noneで非表示にしてるだけ、以上。
5分くらいで実装できたので楽ちんでした。