2010年5月28日金曜日

key chord

Emacsにはキーバインドが不足している。私は矢印キーなどを使う軟弱者なので、幸いC-[bfpn]は開いているが、でも足りない。例えば、replace-stringやreplace-regexpは割と使用頻度が高いが、さてこれをどこに割り当てたものか。あと、1ストロークで実行したいものもたくさんある。
そんな時はkey-chordというelispを使えばいいらしい。(http://www.emacswiki.org/cgi-bin/wiki/download/key-chord.el

;; key-chord
(require 'key-chord)
(key-chord-mode 1)
(setq key-chord-two-keys-delay 0.05)

;; key setting
(key-chord-define-global "gl" 'goto-line)
(key-chord-define-global "as" 'auto-save-buffers-toggle)
(key-chord-define-global "re" 'replace-string)
(key-chord-define-global "zx" 'undo)

key-chord-define-global は、第一引数で指定された文字全てが同時に(key-chord-two-keys-delay秒以内の誤差で)押されたら、関数がコールされるというもの。

例えば、指定行に行きたいときにはgoto-line(M-g g)を使うが、これがgとl同時押しでよいのだ。同じ要領で、reでreplace-stringも使えるようにした。これこそ、私にしてみればワンストロークでやりたかったことだった。
今回は頭文字をとってキーバインドを適当に決めたが、実際にはおしやすさが重要。中途半端に離れているととても打ちづらい。なので、実は現実的な割当数は思ったよりは少ないが、それでも大変な数のキーバインドを手にいれることが出来る。

key-chord.elにはcopyright 2003とか書いてあった。こういうelispを知る度に、一週間くらいずっと拡張ばっかりする時間が欲しいと思うのだが、結局そんな時間は取れた試しが無い。まだ数日しか使っていないが、手放せないelispになりそうだ。

なお、ターミナルではキルリングとクリップボードの共有(とりあえずMac)をやっておかないと、クリップボードから貼りつけると、いろんなキーがほぼ同時に押されたことになって大変なことになるので注意。

キルリングとクリップボードの共有(とりあえずMac)

emacsは独自のキルリングを使っているので、emacsで C-w などでコピーしたところで、例えばFirefoxにそれを貼り付けることはできない。
回避策として、ターミナルなら、それのコピー機能を使用することで、外部アプリケーションに張り付けられる。逆に、クリップボードの文字列も同様の方法でemacsに貼り付けることが出来る。
しかしこれには致命的な欠点があり:
  • 見えたままクリップボードに入るので、ウィンドウ分割していると上手くコピーできない
  • クリップボードからペーストすると、一文字ずつ打ったことになるので、重いしインデントが勝手につく
と、スマートとはいえない状態だ。GUIから起動すると、メニューからコピーなどができるようになっているが、Screenバンザイなのでそちらに行こうとは思えなかった。

そこで、以下のようなelispを、.emacsに書き加えた。(ソース:http://blog.lathi.net/articles/2007/11/07/sharing-the-mac-clipboard-with-emacs
; http://blog.lathi.net/articles/2007/11/07/sharing-the-mac-clipboard-with-emacs
(defun copy-from-osx ()
(shell-command-to-string "pbpaste"))

(defun paste-to-osx (text &optional push)
(let ((process-connection-type nil))
(let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
(process-send-string proc text)
(process-send-eof proc))))

(setq interprogram-cut-function 'paste-to-osx)
(setq interprogram-paste-function 'copy-from-osx)
これでシェアされる。ただしMac限定。
仕組みは簡単で、macのコマンドpbcopyとpbpasteを利用しているだけだ。コマンドの名前があまりにも自明なのであえて説明はしない。
要するに、linux, windowsでも同様のコマンドがあれば、コマンド名の書換だけで使用できるようになる。現在度重なる不幸によって(笑)自分用のubuntu開発機を持っていないので、Linuxでの対応はまたその時にしたいと思うが、少し調べたら同様のコマンドはあるみたいだし、GTKを使えば数行のコードで実現出来るはずだ。

2010年5月18日火曜日

まだまだやりたい事は出来ていない・・・

先日、mikutterの着想から半年が経っていたことに気がついた。途中なんども開発を停止しているし、別のこともいろいろとやっていたので本当に半年やっていたわけではないが、結構経ってしまった。
実際には、CHIを書き始めたのは10月であり、今まで何をしていたんだ、と落胆しそうになったが、とりあえずこれだけの機能がつけられた。
  • ホームタイムライン
  • リプライタイムライン
  • 検索
  • saved search
  • 通知
  • URL短縮
  • リプライ元つぶやきの表示
  • リプライ
  • リツイート
  • 公式リツイート
  • お気に入り
と、非常に少ない。亀進行である。未だにプロトタイプのレベルを出ていない。
主観だが、以下の機能が「普通のクライアント」を名乗るためには足りないのではないだろうか。
  • ダイレクトメッセージ
  • お気に入りに入れたつぶやきのタイムライン
  • スマートリスト(フィルタ)
逆に、現時点では以下の機能が普通のクライアントを上回っていると考えている
  • twitter.comからつぶやきを検索出来る
  • ハッシュタグの内容をmikutterから閲覧出来る
  • Webで保存した検索をタブに表示できる
  • あるつぶやきのリプライ元をノークリックで見ることが出来る
特に検索関係は強い。とりあえずだが自動更新も有り、少し改良すればtsudaる用途にもいい線を行くのではないだろうか。
つぶやきのリプライ元表示は良いアイデアで、構想段階からすでにあった。単純に、フォントを変えて下にリプライ元を表示しているだけだが、これだけでタイムラインの見た目はぐっと変わり、一番の長所といっていい。が、こんなものは簡単にパクられる。
# つぶやきの表示にリストビューを使っちゃった人たちには簡単にはパクれないかもしれない

では、構想段階ではどのようなことを考えていたのか、再び挙げてみたい。これは、12月の時点で既に欲しいと思っていた機能だ(既に実現したものは外している)

  • ダイレクトメッセージ
  • お気に入り
  • ふぁぼられ
  • 特定のつぶやきだけをまとめたリスト(Togetterのようなイメージ)
  • 公式リストへの完全対応
  • フォローしている人一覧
  • フォロワー一覧
  • 特定の人のプロフィール確認
  • 自分のプロフィールの編集
  • フォロー・リムーブ・ブロック・ミュート・マーク
  • スマートリスト
  • つぶやきの永久保存及び検索
  • 画像アップロード
  • 画像インライン表示(少なくともブラウザを介さない)
  • Twitlongerを利用したつぶやきの短縮
  • スレッド
Togetterのようなものだが、これは今はどうかな、と思っている。使いたいケースがあまり思いつかないからだ。何故欲しいと思ったんだろう(とはいえ、この程度のことはプラグインで出来るので、後で作ってもいいかも)。
ミュート、マークはオリジナルの概念だ。ミュートは、フォローしているにも関わらず特定の人のつぶやきを一切ホームタイムラインに表示させない。逆にマークは、フォローしていないにもかかわらず特定の人のつぶやきをホームタイムラインに表示させる。相手に知られること無く、フォロー/リムーブができる。幾つかのクライアントソフトには、既に実装されている。
ミュート、マークはスマートリストで実現可能かもしれない。スマートリストは、簡単なフィルタ言語等でつぶやきを絞り込んで表示するタブで、フィルタ言語にはHatsuneLispを検討している。スマートリストは、ホームタイムラインやリプライタイムラインを実現可能なので、これ一つで大抵のことをしてしまう時がくるかもしれない。
つぶやきの永久保存及び検索は、MySQLとSQLiteを用いて実装したが、万人受けするものではない割にライブラリ等の依存関係がややこしいので配布には至っていない。
最後のスレッドとは、つぶやきの親子関係を再帰的に辿り、一連の会話のツリーを構成するるぶやきをタイムラインに並べる機能。これがあれば、つぶやきを一つ拾えば会話全体が見えるようになり、革新的な機能となるだろう。

かなり盛りだくさんに見えるかもしれないが、これくらいないと使い物にならないと考えている。mikutterは、現在のTwitterクライアントに対する問題提起なのだ。作り始めたきっかけが「良いクライアントがない」という現状をなんとかするため、だったからだ。

こうしてみると、やりたい事の半分以下も出来ていないように見える。しかし、拡張可能な基板は整いつつあり、現在はつぶやきの保存方法すらプラグインで拡張出来るようになっている。つぶやきを投稿したら1秒くらいでフォロワー全員のところに届くのが当たり前の時代もついにすぐそこまで来ているし、半年後は今では想像もできない使い方をしているだろう。
# ハッシュタグとか、去年は公式サポートなかったんじゃなかったっけ・・・あと公式リツイート?検索っていつついたっけ?
とにかく・・・Twitterが本気を出す頃には、Twitterをちゃんと使えるクライアントにしておきたい。

2010年4月2日金曜日

はつねなLispのようなものを考え中

今、片手間にLispのようなプログラミング言語を作っている。プログラミング言語というよりは、処理をデータで表現したかっただけなのだが。

何故作ったし
みくった〜♪を柔軟に拡張できるようにするため

文法
S式とM式を合わせたような文法を採用。略してSMs(ry
だけど見た目はあんまりLispっぽくない。これは、できればプログラマでなくても多少使えるように、などいろいろ考えがある。以下に、みくった〜♪のフレンドタイムラインプラグインのコードを示す。

tl = gen-timeline[200]
regist-window[tl]
onupdate << { (watch msg)
add[tl msg]
}

Lispなんて言わなければ良かった(笑)S式だけで書くと以下のようになるだろう。

(setq tl (gen_timeline 200))
(regist-window tl)
(add onupdate (lambda (watch msg) (add tl msg)))

まず、特記事項はM式だ。これは、S[...]と表記し、(S ...)というリストに展開される。一般的な言語の関数呼び出しf(x)に近い書き方ができるし、S式に慣れていなくても比較的コードが見やすくなる。
次に、演算子。通常Lispでは計算式を次のように書く。

(+ 1 2 3)

いわゆる前置記法でとっつきにくい。演算子がリストの最初以外に現れた場合、その前後の値を括弧で括り、第一要素と演算子を入れ替える。文章では説明しづらいが、要するにパース時に要素の入れ替えが発生するというものだ。
例えば、

1 + 2 + 3
A B + C D
1 + 2 * 3 - 4

は、

(+(+ 1 2) 3)
(A (+ B C) D)
(+ 1 (- (*2 3) 4))

となる。
最後に中括弧だが、これはlambdaの省略記法。

(lambda (a b) (+ (* a a) (sqrt b)))

は、

{(a b) a * a + sqrt[b] }

と書ける。また、シンボル_は、その関数が呼ばれた時の引数リスト、_nのように数字をつければ、n個目の引数に束縛されている。普通の用途ならこれは不要かと思ったが、フィルタを書くために多用することになるので、あえて用意した。

フィルタ関数

では、本題のフィルタにうつる。たとえば、幾つかの優秀なツイッタークライアントでは、「ユーザaか、aへのリプライか、googleが含まれている」つぶやきだけを抽出したタブを作成できるが、これはこう書ける。

{ ()
or{
(assoc[_0 'user] == "a")
include?[assoc[_o 'message] "@a"]
include?[assoc[_o 'message] "google"]
}
}

(※注:orは引数をtが帰ってくるまで順次実行するマクロだが、はつねLispでは表記上の理由からlambdaも渡せる)
ちょっと複雑だ。Rubyだとこうなるだろう。

lambda{ |m|
m[:user] == 'a' or
m[:message].include?("@a") or
m[:message].include?("google")
}

あれ、かわんない。無理もない。はつねLispの関数は、以下の値のいずれかになる。
  1. =演算子でオーバライドされた関数
  2. はつねLispで定義されたプリミティブ関数
  3. 第一引数のクラスのメソッド
  4. 同名のRuby関数
例えばchomp[string]は、Rubyでstring.chompと書くのと同じ意味だ。しかしながら定数にはアクセス出来ないので、例えばnew[Time]のようなことはできない。これはあえて入れた制約で、これによって例えばはつねLispをJavaScriptなどで再実装する場合に、String, Numeric, Listくらいを再実装するだけではつねLispがすべて動かせるようになる。
また、はつねLispはほぼRubyに直訳出来る。プリミティブ関数も短いRubyコードだし、何よりほかのメソッド呼び出しは全てRubyのそれだからだ。つまり、高速化のためにRubyのコードに翻訳することが出来るのだ。

いわば、マクロを使えるようにしたRuby、という感じなのかもしれない。当然、Rubyとちがって全てS式にできるというのが最大のメリットだが。

2010年2月20日土曜日

みくった〜♪3 次までにやること

以前から開発を続けているみくった〜♪だが、テストしてくれている人が増えてきたので、既知のバグがなんなのか、最初のバージョンまでにどんな機能を実現したいのかを明確にしておきたい。

最初のバージョンの目標

目標としてどんな機能を付けるかを列挙しても良いのだが、ここでは「twitte.rbと同じ機能を実装する」とする。
理由は、具体的なクライアント名を上げた方が明確になることと、twitte.rbは基本的な機能をもっているクライアントの中では、機能が少ない方であること。このクライアントには、必要と思われる機能も一部含まれていないが、今回はあえてtwitte.rbに存在しない機能はこれ以上実装しない(削除機能、ふぁぼったつぶやき一覧など)。
なお、twitte.rbにある「アイコンアルバム」は今回実装しない。というのも、なくてもさしあたって困らないからだ(そのうち実装するつもり)。

人柱版までにやること

MMI作成時にフォーカスを移す
ボタンクリックで無数につぶやき入力欄を増やせるMMI(Multi Mumble Input)だが、これを作成した時に入力欄にフォーカスがいかないと、入力欄一つのインターフェイスよりクリック数が増えてしまう。
メモリバカ食いをやめさせる
つぶやきが溜まると、それを破棄しない仕様になっているため、タイムラインの流れが早い場合にメモリを数百MB消費してしまう場合がある。ページングすると操作性が落ちてしまうが、表示されていない部分についてはメモリを開放したりして、メモリ消費を抑える工夫をしなければならない。
ふぁぼる/アンふぁぼ
他人のつぶやきをお気に入れる/外す機能。
URL開く
URLをつぶやく人は多い。今はコピーできるようになっているが、クリックだけで開けるようにするべき。
ショートカットキーによる投稿(Ctrl+Enterとか)
現状、ボタン押下による投稿のみしか対応していない。
設定変更プラグイン
要するに、設定変更画面。内容は詳しく詰めていないが、以下のような物が最低限必要だと思う
  • 通知機能(サウンドを鳴らす、inotify、コマンド実行等)
  • 更新間隔(現在は一分固定、リプライは20分)
  • アカウント情報の変更
初回のアカウント入力/アカウント変更
現在、initialize.rbを実行することで初回の設定をするが、mikutter.rbを起動した時点でこれをするべき。
ポストする時にハッシュタグが2つつく
#mikutterなどとハッシュタグをつけると、#mikutter #mikutterと投稿される。
リプライ送るときに、宛先がデフォルトで入ってない
送信時に補完していたが、残り字数がわからなくなる。
<>問題
<>などがエンティティエンコードされた状態で表示される。
140文字に切り詰める
クライアントがこれをしないと、Twitterは140字以上の投稿をはじいてしまう。

是非ともやっておきたいこと

IMEのデフォルトONオプション
毎回つぶやき入力欄が消えるため、設定によっては毎回半角入力モードになってしまっている。
ダイレクトメッセージの実装
ただし、これはユーザのプロフィール画面と密接に関わる。そのため、今回はごく簡単なものになると思われる。

余裕があればやること
これは絶対に将来的にやりたい事だが、今回やろうとして却下したもの。理由は上記の通り、twitte.rbに実装されていないからだ。
  • 短縮URL
  • 画像表示
  • 自分のつぶやきを削除
  • スキン機能、というか見た目変更機能(フォントや文字色、背景など)
  • スクロールロック
もしかしたら、見落としているだけで実装されているかもしれないが、今回はこれらを見送る。なお、付けたい機能はこの他もいくらでもある。

まとめ

今回は、直近のやることをまとめた、いわばメモのようなものをかいたが、リリース前なので実装したい機能というよりは、バグ修正と最適化が主になっている。
次回くらいには、ここや私のWebページで「みくった〜♪」を配布したいと思っている。

2010年2月16日火曜日

みくった〜♪2 ちょっと作ってみた

みくった〜関連の記事しか書き込んでいないけど、それしかやっていないので。
ある程度インターフェイスがしっかりしてきたので、まだ殆どみっくみくにされていないけどスクリーンショットを公開する。なお、Ubuntu 9.10で撮影した。



これがフレンドタイムライン。いわゆるTL。モザイクの行は「toshi_a 伊吹萃香」のように表示されている。ツールバーの「つぶやく」ボタンや、各つぶやきにある「@」「RT」ボタンを押したらつぶやきを入力するスペースが現れる。普段表示しないことにより、つぶやきを少しでも多く表示出来るようになっているし、猫につぶやかれる心配も減るかもしれない。

目玉機能のマルチつぶやき機能。だけど名前を付けておかないとパクられたときに残念な気持ちになるので「Multi Mumble Input(MMI)」という名前を付けておく※1。つぶやきボタン等は、押せばいくらでも量産できるようになっているので、つぶやきを書いている途中で別のつぶやきにリプライを送りたくなったりしても、その内容をわざわざ覚えておいたり、書きかけのつぶやきを消す必要はない。それを覚えておくのはみくった〜♪の仕事なのだ。
※1 というか、パクられるまでになれたら嬉しいんだけど


リプライ画面。先ほどと基本的には変わらない。リプライ画面に限ったことではないが、カーソルを合わせたつぶやきが別のつぶやきへの返事だった場合、親つぶやきがツールチップで表示される。
表示方法はともかくとして、あるリプライが何に対してなのかが分からなくなることというのは、複数人と会話していたらよくある話だ。これが確認出来るクライアントが当然多く使われているはずだが、その数はそんなに多くないし、しかも大抵のクライアントでは相当確認が面倒だ。
・・・ということを考えると、現時点ではついったーでよく会話をする人に適したものになっていると考えられる。もちろん、通知機能、URLを開く機能など基本的な機能が揃っていないのでまだ使ってもらえる段階にも無いが、twitte.rbを超えるという最初の目標はすぐそこだ。

まとめ
今回は、現在の開発の進捗を報告した。今後の課題は、見た目がみっくみくにされていない点である。

2010年2月10日水曜日

みくった~1 バージョン1の全貌

ついったーでわいわい言っていたが、ちゃんとまとめてなかったのでまとめる。
前回は動機を語ったので、今回は短期目標を具体的に語る。

とりあえず短期目標として、最低限、他のクライアントにある機能はつけたい。もっとも機能が多いと思われる夜フクロウに勝てばいいだろうと思ってる。
しかし短期目標には目標が高すぎる感があるので、まず、みくった~にコードの一部をいただいたtwitte.rbにある機能を網羅し、それを以ってバージョン1としたい。
だけど、あのクライアントにある機能で実装しないものも多いので、ここに最初の搭載予定機能を書いておく。

まずタブには、フレンドタイムライン、リプライ、DM、設定が並ぶ。

DMのタイムラインは大体どのクライアントにもあるし、実装が容易なのでとりあえず実装するが、どちらかというとフォロワーのプロフィールからその人だけを絞ったりできるようにしたい。

つぶやき入力欄が特徴的で、デフォルトでは表示されていない。ボタンを押すことで次々と入力欄を作れる。

各つぶやきにはリプライボタンが付いていて、クリックするとその下につぶやきが入力できる。これも、複数の同時入力に対応している。

またあるつぶやきをダブルクリックすると、それがなにかに対する返信だった場合に、それを再帰的に辿ってタイムラインを作るので、何に対する返事なのかが一目瞭然になる。

設定がタブに埋め込まれているのは、ボタンを置くスペースが無かったから。右クリックメニューからしか開けない、ということにしてもいいかもしれないが、いちいちポップアップにする必要もなさそうだ。
設定項目は次のものを予定する。タイムライン、リプライ、DMの通知方法(inotify、サウンド、任意のコマンド)。アカウント情報。更新頻度。そしてフッダ。各プラグインに関して設定が増えると思うがいまはこんなものだろう。

とりあえず、機能としては何もないに等しいがこれくらいでリリースする(すごいのに期待してた人ごめんなさい。でもこれからだ)。近いうちに、将来つけたい機能もまとめる。

次回は、プラグインによる機能拡張について書く。と思う。


その他
今回はiPhoneから書いてみた。やっぱりキーボードがいい!