Amon2::Liteでmarkdownその他のリアルタイムプレビュー - すぎゃーんメモで、markdownとかのリアルタイムプレビューできるものを作って試してみたもの、やっぱりテキストエリアでmarkdownを書くってことはあまりしないなー、と思い。
大抵は使い慣れたエディタを使って編集すると思うので、それが変更されたときにブラウザ上で自動更新される方が嬉しいような気がして、
というものを作ってみた。
Node版
まずはNodeで。実行時引数で監視対象ファイルを指定し、fs.watchFile
でそれを500msごとに監視、変更あれば変換したHTMLを普通にSocket.IOでクライアント側に通知する。
#!/usr/bin/env node var fs = require('fs'); var http = require('http'); var md = require('markdown'); var target = process.argv[2]; if (! target) { console.error('usage: ' + process.argv.join(' ') + ' <filename>'); process.exit(1); } var server = http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end( '<!DOCTYPE html><html><head><script type="text/javascript" src="/socket.io/socket.io.js"></script>' + '<script type="text/javascript">var socket = io.connect();socket.on("change", function (html) { document.getElementById("preview").innerHTML = html; });</script>' + '</head><body><div id="preview"></div></body></html>' ); }); server.listen(3000); var io = require('socket.io').listen(server); fs.stat(target, function (err, stat) { if (err) { throw err; } if(! stat.isFile()) { console.error(target + ' is not file'); process.exit(1); } fs.watchFile(target, { interval: 500 }, function (curr, prev) { fs.readFile(target, 'utf8', function (err, text) { if (err) { throw err; } io.sockets.emit('change', md.parse(text)); }); }); });
Perl版
そういえばPerlでもPlack::Middleware::SocketIOっていうSocket.IOのサーバ実装のモジュールがあったはず、と思ったらいつの間にかDEPRECATEDになっていた。PocketIOというのを作っているのでそちらを代わりに使え、ということらしい。
GitHub - vti/pocketio: SocketIO PSGI App
まだCPANに上がってないしなんかテストがこけてしまったけどとりあえず無理矢理使ってみた。
#!/usr/bin/env plackup use strict; use warnings; use Encode 'decode_utf8'; use Plack::Builder; use PocketIO; use Path::Class 'file'; use Amon2::Lite; use Filesys::Notify::Simple; use Text::Markdown 'markdown'; shift; # psgi my $target = shift or die; -f $target or die; $target = file($target); get '/' => sub { my ($c) = @_; return $c->render('index.tt'); }; builder { mount '/socket.io' => PocketIO->new( handler => sub { my $self = shift; my $watcher = Filesys::Notify::Simple->new(['.']); while (1) { $watcher->wait( sub { my @events = @_; for my $event (@events) { next if $event->{path} ne $target->absolute; my $text = $target->slurp; $self->send_message({ html => decode_utf8(markdown($text)), }); } }, ); } }, ); mount '/' => __PACKAGE__->to_app; }; __DATA__ @@ index.tt <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>preview</title> <script type="text/javascript" src="https://raw.github.com/LearnBoost/socket.io-client/master/dist/socket.io.js"></script> <script type="text/javascript"> var socket = io.connect(); socket.on('message', function (msg) { document.getElementById('preview').innerHTML = msg.html }); </script> </head> <body> <div id="preview"></div> </body> </html>
ファイルの変更監視にFilesys::Notify::Simple
を使用。ちょっと書き方はイケてないかも知れないけど、とりあえずNode版と同じようには動作した。拡張子で判定とかやれば他の記法のも簡単に同じようなもの出来るかな。