hatena-mode を拡張してみた。

最近の Web 巡回スタイルと言えば、FEEDBRINGER で取得した RSS を読みながら、気になる記事を見付けたら MM/Memo に登録し、気が向けばコメントしてくというものです。
そのため、Web 巡回には emacs-w3m をめっきり使わなくなり、Firefox ばかりになってしまいました。
そして、Firefox ばかりだと hatena に書き込みする気がまったく起きないのでした。(MM/Memo でコメントを書くだけでも、その操作のし難さにはストレスを感じてしまいます。何であんなに重いんでしょうか……)

この「feed を読んで bookmark する」というスタイルを、Emacs から出来れば良いのですが、emacs-w3m は、流行の Ajax インタフェースを持つ site には役に立ちません。

Emacs 上で動作する RSS Reader は、以前に少し探したときには NewsTicker しか見付けられませんでした。
自分としては、これだとちょっと微妙なのです。

取り敢えず、RSS を読むのは Firefox で仕方ないとして、気になった記事について hatena に記述する気になるにはどうすれば良いかと考えたところ、MM/Memo に bookmark したら、それを emacs-w3m で開いて hatena-mode で記事を書く、というシーケンスくらいしか思い付きません。これだとアクションが多くなって余りよろしく無いのですが、その際、簡単に言及リンクが記述できれば、少しはその気になるかもしれません。

と言う訳で、

M-x hatena でバッファを開くときに、コマンドを実行したバッファが emacs-w3m のバッファで region を選択していれば、選択範囲の文字列を抽出して言及リンクを挿入する。

このとき、選択範囲内に anchor があれば、その anchor に設定されている url を利用し、無ければそのバッファが訪問している url を利用して言及リンクを生成する。

様にしてみました。

(defvar hatena-util-url nil)
(defvar hatena-util-string nil)
(defvar hatena-util-anchor nil)

(require 'w3m)
(defun hatena-util-pickup-reffer-anchor (&optional opt)
  (interactive "P")

  (let* ((start (if (or (and (boundp 'transient-mark-mode) transient-mark-mode
                             (boundp 'mark-active) mark-active) ; for emacs
                        (and (fboundp 'zmacs-activate-region)
                             zmacs-region-active-p)) ; for xemacs
                    (region-beginning)))
         (end (and start (region-end))))

    (when (string= (symbol-name major-mode) 'w3m-mode)
      (setq hatena-util-string (buffer-substring start end))
      (when start
        (save-excursion
          (goto-char (next-single-property-change start 'w3m-href-anchor))
          (setq hatena-util-url (or (and (<= (point) end) (w3m-anchor))
                                    w3m-current-url))))
      (message hatena-util-url)
      (when (and hatena-util-url hatena-util-string)
        (setq hatena-util-anchor
              (concat
               "<a href=" hatena-util-url ">" hatena-util-string "</a>"))))))

(defun hatena-util-insert-reffer-anchor ()
  (interactive)

  (if hatena-util-anchor
      (insert hatena-util-anchor)
    (message "no anchor.")))

(defun hatena-util-cite-reffer-anchor ()
  (interactive)

  (if hatena-util-anchor
      (progn
        (insert ">|\n  ")
        (hatena-util-insert-reffer-anchor)
        (insert "\n|<\n"))
    (message "no anchor.")))

ってな関数と変数を定義しておき、

(defadvice hatena (around hatena-disable-insert-template activate)
  (unless (boundp 'html-helper-build-new-buffer)
    (load "psgml-html"))
  (setq hatena-util-url nil
        hatena-util-string nil
        hatena-util-anchor nil)

  (let ((html-helper-build-new-buffer nil)
        (insert-flag nil))
    (hatena-util-pickup-reffer-anchor)
    (when (memq hatena-today-buffer (buffer-list))
      (setq insert-flag t))
    ad-do-it

    (when insert-flag
      (goto-char (point-max))
      (while (= (char-before) ?\n)
        (delete-char -1))
      (insert "\n\n")
      (insert "*[] ")
      (goto-char (- (point) 2)))
    (when hatena-util-anchor
      (save-excursion
        (goto-char (point-max))
        (insert "\n\n")
        (hatena-util-cite-reffer-anchor)
        (insert "\n")))))

と advice しています。

hatena-util-* という変数群は、当初、let () 内部で束縛するだけの local な変数としていたんですが、anchor を生成し、貼り付ける動作を、M-x hatena したとき以外にも利用できる様にしようと思い、独立した変数にしてみました。
hatena-util という prefix は、取り敢えず本家 hatena-mode.el で使われていないのでこの様に書きましたが、バッティングし易い名前なので注意しておいた方が良さそうです。 ;; いつも、こういう名付けで悩んでしまうんだよなあ。

さーて、使いものになるでしょうか。