Google Desktop で howm の検索を(一部)高速化

4年程 howm を愛用している。
howm ファイルは1日1ファイルベースで、いまや1000個弱に近づいた。
ここ最近は、C-c , g や C-c , s での全文検索があまりに遅くて耐え難い。
遅いといっても10秒ちょっと待てば結果が出るのだが、多用するにはストレスが溜まる。
マシンのスペックを上げればいいのかもしれないが (現在 Pen4 3.2GHz, 1GB RAM)、
そう簡単にもいかないのが不況下の職場の辛いところ。

そんなときこそソフトウェアによる高速化だ!
まずは howm-view-use-grep を t にして、
検索を cygwingrep にやらせてみたけど、全然早くならねー
元々の fake-grep との違いがほとんど感じられない。これはだめだ。

もう少し調べてみると、namazu だの rast だのを導入すると早くなるっぽい。
けど、面倒そう。(ちゃんと調べてないので本当は簡単かも)

そこで、かなり昔から話題になっていた Google Desktop を導入してみた。
Google Desktopgrep 風に扱うための gdsgrep.rb なんてのもあるみたいだし、
これを howm から外部 grep として使わせれば楽勝!第三部完!
なんて軽い気持ちで取りくんでみたが、楽勝ではなかった。

まず、Google Desktop の検索は正規表現とか無理。(ですよね?)
さらに、ファイル内のキーワード出現位置(行数)とか教えてくれない。
これじゃ grep としての機能を果たせないよー

ということでメタヒューリスティック的に(合ってる?)
Google Desktop でファイル検索範囲を絞り込んでから、
普通に grep で検索をかけるので攻めてみた。

結果、正規表現は使えないけど、たいていの検索ではかなりの高速化が達成できたので、
以下に elisp を公開します。
たまに結果を取りこぼしたりしてるみたいだけど、
そこら辺はメタヒューリスティック(合ってる?)ということでご愛嬌

ちなみに WindowsMeadow 3 でしか試してません。
ブログのタイトル通り、何がおきても一切保証しません。
dolist のあたりとかぐちゃぐちゃですが気にしません。


2010-10-24 追記
上の記事は howm ファイルが Google デスクトップによって全文検索されることを前提として書いていますが、デフォルトの設定ではそうはならないかもしれません。
うまくいかない場合、howm ファイルの拡張子を .txt 等の全文検索対象拡張子に変えるか、Google デスクトップに Larry's Any Text File Indexer 拡張(テキストファイル全般を全文検索の対象にする拡張)をインストールする等してみてください。

;;; howm-gds.el --- howm with Google Desktop

;; Copyright (C) 2009  

;; Author:  yamdan <yamdan@gmail.com>
;; Keywords: howm, gds

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;; Setup:
;;
;;   Install Google Desktop, and add to your .emacs:
;;
;;   (require 'howm-gds)
;;   (setq howm-gds-search-default-dir "c:\\path\\to\\howm")
;;
;;   * edit "c:\\path\\to\\howm" to your howm directory.
;;

;;; Code:

(require 'howm)

(defvar howm-gds-search-url
  (if (functionp 'mw32-registry-get)
      (car-safe (mw32-registry-get "HKEY_CURRENT_USER\\Software\\Google\\Google Desktop\\API""search_url")))) 
(defvar howm-gds-search-default-dir "c:\\path\\to\\howm")
(defvar howm-gds-search-max-num 1000)
(defvar howm-gds-switch-original nil)  ; for debug


(defun howm-gds-call-view-search (regexp fixed-p &optional emacs-regexp)
  (let ((hilit (if emacs-regexp
                   `((,emacs-regexp . howm-view-hilit-face))
                 nil)))
    (howm-view-search-folder regexp
                             (howm-gds-search-path-folder regexp) ; 検索範囲を GDS で絞込
                             nil nil fixed-p hilit)
    (howm-record-view-window-configuration)))

(defun howm-gds-list-reminder (types name)
  (let* ((r (howm-reminder-regexp types))
         (rg (howm-reminder-regexp-grep types))
         (summarizer (howm-reminder-summarizer r t))
         (folder (howm-reminder-search-path-folder)))
    (howm-view-search-folder rg (howm-gds-search-path-folder rg)
                             name summarizer)
    (howm-list-exclude)
    (howm-reminder-add-font-lock)
    (howm-mode-add-font-lock)
    (let ((action-lock-default-rules
           (howm-action-lock-reminder-forward-rules t)))
      (action-lock-mode))))

(defun howm-gds-search-path-folder (regexp)
  (if howm-gds-switch-original
      (howm-search-path-folder)
    (let ((files (howm-gds-search-filepath regexp)))
      (if files
          (howm-make-folder:files files)
        (howm-search-path-folder) ; GDS による絞込に失敗したら、通常の検索範囲を設定
        ))))

(defun howm-gds-search-filepath (regexp &optional dir)
  (let* ((dir (or dir howm-gds-search-default-dir))
         (query (howm-gds-url-encode-string regexp 'utf-8))
         (in-dir (howm-gds-url-encode-string dir 'utf-8))
         (buf (url-retrieve-synchronously
               (concat
                howm-gds-search-url
                "&ie=utf-8"
                "&adv=1"
                "&has=" query
                "&type=cat_files"
                "&num=" (number-to-string howm-gds-search-max-num)
                "&in=" in-dir
                "&under=on"
                "&format=xml")))
         filepath-list)
    (save-excursion
      (set-buffer buf)
      (let* ((results-set (xml-parse-region (point-min) (point-max))))
        (dolist (results-elt results-set)
          (and (listp results-elt) (equal (car results-elt) 'results)
               (dolist (result-elt (xml-node-children results-elt))
                 (and (listp result-elt) (equal (car result-elt) 'result)
                      (let* ((url-elt (assoc 'url (xml-node-children result-elt)))
                             (url (and (listp url-elt) (car-safe (xml-node-children url-elt)))))
                        (and url (add-to-list 'filepath-list url)))))))))
    filepath-list))

;; refer to w3m-url-encode-string (in w3m.el)
(defun howm-gds-url-encode-string (str &optional coding)
  (mapconcat
   (lambda (ch)
     (cond
      ((eq ch ?\n)                      ; newline
       "%0D%0A")
      ((string-match "[-a-zA-Z0-9_:/.]" (char-to-string ch)) ; xxx?
       (char-to-string ch))             ; printable
      ((char-equal ch ?\x20)            ; space
       "+")
      (t
       (format "%%%02X" ch))))          ; escape
   ;; Coerce a string into a list of chars.
   (append (encode-coding-string (or str "")
                                 (or coding
                                     'iso-2022-jp))
           nil)
   ""))

(defalias 'howm-call-view-search 'howm-gds-call-view-search)
(defalias 'howm-list-reminder 'howm-gds-list-reminder)


(provide 'howm-gds)
;;; howm-gds.el ends here