Emacsからはてなダイアリーに投稿できるようにする試みはやり尽くされている感じがするけれど, 古すぎたりどうもしっくりこなかったりしたので, 自分で一から実装した.
やりたいこと
既存のやり方
hatena-mode
hatena-modeによれば, http://d.hatena.ne.jp/hikigaeru/20040617#p1を参照せよということだけど, プライベートモードになっていて閲覧できないので使えず.
hatena-diary-mode
http://hatena-diary-el.sourceforge.jp/
- hatena-modeから派生したプロジェクトらしい.
- 下書きは未対応?
はてな記法をハイライトするために, メジャーモード部分だけでも使おうかと思ったけれど, なんか2色くらいしか定義されてなくて割と残念な感じに表示されたのでやめた.
simple-hatena-mode
http://coderepos.org/share/wiki/SimpleHatenaMode
下書きの対応が微妙なところがつらい. はてな記法のハイライトはだいぶましだけど(ソースコードを見た限りは)個人的にはやっぱり気き入らない感じだった.
あとは最初試そうとしたときにCodeReposが落ちていて, あんまりCodeReposに上がっているパッケージは使いたくないな, と思った. なので実際に試してはいない. これを使うせいで, はてダラとCodeReposに依存してしまうのはリスクだと判断した.
hatedara-mode
http://d.hatena.ne.jp/amt/20070828/HatedaraMode
simple-hatena-modeがこれを参考に機能拡張されている感じなので試さなかった.
ya-hatena-mode
https://github.com/takaishi/ya-hatena-mode
設計思想としてはこれが一番しっくりくる. メジャーモードはないけれど, 欲しかったら別のパッケージを使ってね, というのもよい. ただ, 実装を洗練させる前に開発者が別のブログに移行してしまったようなので完成度があと一歩なのが残念. たとえばふつうのバッファの保存でアップロードしてくれるようなことはない. あと個人的には無駄にAnythingを使ったインタフェースは操作しにくかった.
最終的には, 最初はこれのAPI部分を使い回しつつインタフェースのプロトタイプを実装して, 動くようになったらAPI部分もインタフェースとあわせやすいように再設計して実装しなおした*1.
HatenaDiaryFS
http://tarao.hatenablog.com/entry/20091102/1257201079
今まではこれで書いていた. すべてのものがファイルとして表現されて, アプリケーションはファイルさえうまく扱えればよい, というのは思想的には非常に素晴らしい. ただこれは実際のところ以下の点が結構めんどくさかった.
- 使うときにマウントして終わったらマウント解除
- 新規作成と編集が異なる操作
- 保存がけっこうもっさりする
つくったもの
- hatena-diary.el
- はてなダイアリーを操作するユーザインタフェース
- hatena-diary-api.el
- はてなダイアリーをAtomPubで操作するAPI
- hatena-markup-mode.el
- はてな記法のためのメジャーモード
- hatena-multi-mode.el
- スーパーpre記法部分だけ別のメジャーモードにする
特徴
配布場所と依存パッケージおよびインストール方法
ファイル | URL | 依存パッケージ |
---|---|---|
hatena-diary.el | https://gist.github.com/4465244 | |
hatena-diary-api.el | https://gist.github.com/4465244 | flim |
hatena-markup-mode.el | https://gist.github.com/4428666 | |
hatena-multi-mode.el | https://gist.github.com/4475652 | multi-mode, multi-mode-util |
上記ファイル(のうち必要な機能のもの)と依存パッケージをダウンロードしてload-path
上のどこかに置く. el-getを使っている人のために末尾にレシピを記載.
flimへの依存はsha1-el.elだけなので, flim全体をインストールしなくてもこれだけ入れれば問題ない.
設定
パッケージ
基本的にはrequire
するだけ.
(require 'hatena-diary)
hatena-markup-mode
を編集時に使いたい場合は, 続けて
(require 'hatena-markup-mode) (setq hatena:d:major-mode 'hatena:markup-mode)
などとしておく. これをしなかった場合の初期値はhtml-mode
になっている.
スーパーpre記法の内部で別のメジャーモードを自動的に有効にする場合は
(require 'hatena-multi-mode) (add-hook 'hatena:markup-mode-hook #'hatena:multi-mode)
などとしておく. この機能自体はhatena-markup-mode
とは独立しているので, hatena:markup-mode-hook
の部分は使いたいメジャーモードに合わせて適宜変更する.
アカウント
アカウント情報は, 最初にサーバにアクセスする際に入力を促される(一度入力すればEmacsを終了するまで記憶される). もし毎回入力するのが嫌な場合は, 以下のようにして設定できる.
(setq hatena:username "ユーザ名" hatena:password "パスワード")
実際には上記のように書いてパーミッション600等で保存したファイルをロードするようにした方がよい.
サブアカウントを常に使いたい場合は
(setq hatena:d:username "ユーザ名")
追記: 2014-11-30
2014-03-05時点で, 通常のログインパスワードでの認証は廃止されています. hatena:d:password
にAPIキーを指定することで, 引き続き利用可能です. 自分の日記のAPIキーは, メール投稿の設定画面から確認できます. 「投稿用メールアドレス」の@
の前の部分がAPIキーです.
アカウント設定を暗号化する
EmacsではEasyPG Assistantでファイルを簡単に暗号化できるので, これを使うのが簡単.
まず, ~/.emacs.d/.hatena-credentials.gpgというファイルを作成して,
(setq hatena:username "ユーザ名" hatena:password "パスワード")
の設定を書いておく. 保存すると, 暗号鍵を訊かれるので適当に選択する.
アカウント情報を読み込む設定では
(load "~/.emacs.d/.hatena-credentials.gpg")
とすれば.elでなくても読み込めて, 読み込むときに復号化される.
復号化のためのパスフレーズをEmacs起動時に入力したくないというような場合は, hatena-diary.elをrequire
せずにautoload
で読み込むようにして, eval-after-load
でアカウント情報を読み込むのがよい.
(autoload 'hatena:d:list "hatena-diary" "List Hatena::Diary blog entries in a buffer." t) (autoload 'hatena:d:list-draft "hatena-diary" "List Hatena::Diary draft entries in a buffer." t) (eval-after-load 'hatena-diary '(load "~/.emacs.d/.hatena-credentials.gpg"))
Evilユーザのための設定
Evilを使っている場合のみ必要な設定.
日記や下書きの一覧でのキーがEvilのキーと衝突しないようにするには以下の設定が必要(Evil本体に書かれているBuffer-menu-mode
の設定と同じことをする).
(push 'hatena:d:list-mode evil-motion-state-modes) (evil-make-overriding-map hatena:d:list-mode-map) (evil-add-hjkl-bindings hatena:d:list-mode-map 'motion)
hatena-multi-mode.elを使う場合は
(require 'multi-mode+evil)
も忘れずに. (ViperやVimpulseを使っている場合はmulti-mode+viper
.)
使い方
コマンド
M-x hatena:d:list
- 日記一覧を開く
M-x hatena:d:list-draft
- 下書き一覧を開く
C-u M-x hatena:d:list
- ユーザ名(サブアカウント)を指定して日記一覧を開く
C-u M-x hatena:d:list-draft
- ユーザ名(サブアカウント)を指定して下書き一覧を開く
M-x hatena:d:new
- 新しい日記を書く
M-x hatena:d:new-draft
- 新しい下書きを書く
一覧を開いてしまえば, エントリを選択して編集したり, ショートカットキーで新規作成したりできるので, 最悪最初の2つだけ覚えておけばいい.
日記一覧
日記一覧では以下のキーが利用可能.
q
- 一覧を閉じる
g
- 一覧を更新
p
- 前のエントリを選択
n
- 次のエントリを選択
N
- 次のページを読み込む
RET
- エントリを編集
V
view-mode
でエントリを開くv
- プレビューモードのon/off
d
- 削除マークをつける
P
- 公開マークをつける(下書き一覧の場合のみ)
u
- マークを消す
x
- マークのついたエントリに操作を適用
c
- 新しい日記を書く
C
- 新しい下書きを書く
一覧は最初に開いた時点では直近20件しか取得しない. 以降はN
キーを押すか, あるいは一覧の一番下までカーソルを持っていくと, 次の20件を読み込む.
プレビューモードがonになると, 別ウィンドウに選択中のエントリのプレビューを表示するようになる. 日記一覧の場合, プレビューはHTML断片で, w3mがインストールされていればw3mを使ってレンダリングし, そうでなければhtml-mode
でソースを表示する. 下書き一覧の場合, プレビューは元のはてな記法のソースで, 編集時に使うメジャーモードで表示する.
編集
日記エントリの場合は~/.emacs.d/hatena/diary-USER-YYYYMMDD-1234567890, 下書きエントリの場合は~/.emacs.d/hatena/diary-draft-USER-1234567890のような仮想的なファイル名が付与される(1234567890の部分はUNIX時刻). また新規作成時はnew-hatena-blog-entry, new-hatena-draft-entryのような名前でバッファを開いて, 初回保存時に日付を伴ったファイル名に変更される. 実際にこれらのファイル名が使われるのは, AtomPubによるアップロードが失敗した場合と, hatena:d:no-auto-save
をnil
に設定していて自動バックアップが作られる場合のみなので, ディレクトリ~/.emacs.d/hatena/を作らないでおいても動作する(アップロードが失敗した場合は単に保存に失敗したことになる).
保存は通常のバッファの保存(save-buffer
)でできる. 保存によってアップロードが成功した場合は, "HTTP/1.1 200 OK"や"HTTP/1.1 201 Created"のようなメッセージが表示される.
編集時に使うメジャーモードはhatena:d:major-mode
変数で設定すること.
スーパーpre記法ごとにメジャーモードを変える
hatena-multi-mode.elを使うと, スーパーpre記法の内部では指定した言語のメジャーモードを使うようにできる. ただし, スーパーpre記法の言語の名前とEmacsのメジャーモードの名前は必ずしも対応しないので調整が必要な場合もある*2.
スーパーpre記法で指定した言語に対応するメジャーモードが見つからない場合は, その言語指定部分をハイライトした上で"Cannot find major mode for file type 'LANG'"のようなメッセージが出るので, その場合は以下のいずれかの対処が必要.
- LANGと同名(もしくはLANG-modeという名前)のメジャーモードは存在するけれど, Emacs標準では入っていないという場合は, そのメジャーモードをインストールする
- LANGとは別名のメジャーモードを使いたい場合は
hatena:mm:filetype-alist
変数に指定する
たとえば,
>|ocaml| ... ||<
というスーパーpre記法でtuareg-mode
が使いたいなら,
(push '(ocaml . tuareg) hatena:mm:filetype-alist)
とする.
あるいは, そもそもocaml-mode
という名前の関数をtuareg-mode
の別名として扱ってしまっても問題ない場合は, hatena:mm:filetype-alist
には手を加えずに,
(fset 'ocaml-mode 'tuareg-mode)
のようにした方がいい.
ちなみに, LANGがファイルの拡張子そのもので, auto-mode-alist
でその拡張子のためのメジャーモードを指定している場合は, 何もしなくても正しくメジャーモードが選択されるので, 気にしなくてもいい.
メジャーモードはカーソル位置によって切り替わり, 裏側では別のメジャーモードでは別の間接バッファに移動するようになっているので, カーソルがスーパーpre記法の内部に入らないとハイライトされない. 加えて, font-lock-mode
の一般的なやり方を想定しているため, メジャーモードがあまりに特殊な場合はうまくいかないこともある.
既知の問題や未対応な部分
1つ目はそのうち修正する予定. 2番目は要望があればなんとかするかも. 下2つはAPIが提供されない限り対応するつもりはない.
所感
この日記をさっそくhatena-diary.elで書いてみたところ, HatenaDiaryFSと比べて保存時の動作が圧倒的に軽快で, とても心地よかった. 以前書いた日記を参照するのも楽で助かる.
実装は細かな修正を除けば2日くらいでできてしまって楽ちんだった. tabulated-list-mode
べんり.
追記
2013-01-10T22:14+0000 ブックマークコメントへの返信
ちょっと未確認なのですが, AtomPub APIの仕様で言うところのupdated
要素が「ちょっとした更新」ではない更新のために指定するものだとすると, 現状の実装ではすべての更新は「ちょっとした更新」になる(updated
は指定しない)ようになっています. 逆にupdated
を指定した更新は現状ではできません(要望があればできるようにするかもしれません).
確認しました. AtomPub APIで「ちょっとした更新」を扱う方法はないようです(少なくともupdated
を指定したかどうかで違いはありませんでした). 保存した場合は必ずふつうの更新になります.
2013-01-11T14:26+0000 機能追加
C-u M-x hatena:d:list
でサブアカウントの日記一覧を開けるようにしたM-x hatena:d:save-as-draft
で日記エントリを下書きとして保存できるようにした
2013-01-12T10:54+0000
- アカウント情報を暗号化して保存しておく方法を記載
2013-01-26T02:25+0000 機能修正
- アカウント情報を設定していない場合は入力を促すようにした
- 編集バッファでメジャーモードを変更してもアップロードができるようにした
- スーパーpre記法内で保存すればアップロードされるようにした
2013-03-25T09:57+0000 バグ修正
- ユーザIDが「-」を含むとうまく動作しなかったのを修正