LISPUSER

LISPMEMOQ: How can you tell when you've reached Lisp Enlightenment?
A: The parentheses disappear. -- Anonymous

(top)  (memo)  (rss)

Emacs と全文検索 Hyper Estraier を使う

howm の記事やメールなどが増えてきて探すのが面倒になってきたので全文検索 の導入を考えはじめました.まず Hyper Estraier がよさそうなので,評価も とりあえずなんとか検索できるような Emacs Lisp ででっちあげました.

設定

  1. HyperEstraier をインストールする (estcmd にパスが通っている事)
  2. hyperestraier-config を設定する
    • :linux プラットフォーム
      • :howm 種別
        • :index インデックスのディレクトリへのパス
        • :create インデックス作成時のコマンド
        • :update インデックス更新時のコマンド

この設定の部分でインチキ臭ささが酷いですね.なんと NTEmacs でも動かした い,かつ,ファイルの指定は find ... |grep のように指定したかったと いう個人的要望で,なんと .bat というバッチファイルを生成してシェルから 実行するという手抜きっぷりです.

使い方

M-x hyperestraier-make-index
   種別を聞いてくるので、答えるとインデックスを作成する (:create で指定したコマンドラインを呼び出すだけ)

M-x hyperestraier-update-index
   種別を聞いてくるので、答えるとインデックスを作成する (:search で指定したコマンドラインを呼び出すだけ)

M-x hyperestraier-search
   種別、検索フレーズ、結果の表示方法を指定して検索する (:index で指定した場所のインデックスを検索する)

ToDo

  • 検索結果バッファ用のモードを用意する (考えてるのは↓のような簡易的なもの)
    • p: 前の検索結果へ
    • n: 次の検索結果へ
    • v: 検索結果のファイルを開く とか?
  • Mew との連係
    • タグによる分類とかつけたいので結局 C で HyperEstraier の API を利用する
;;; HyperEstraier.el - Full Text Search Support for Emacs
;;;
;;; [設定]
;;;
;;;   1. HyperEstraier をインストールする (estcmd にパスが通っている事)
;;;   2. hyperestraier-config を設定する
;;;      + :linux プラットフォーム
;;;         + :howm 種別
;;;            + :index インデックスのディレクトリへのパス
;;;            + :create インデックス作成時のコマンド
;;;            + :update インデックス更新時のコマンド
;;;
;;; [使い方]
;;;
;;;  M-x hyperestraier-make-index
;;;
;;;    種別を聞いてくるので、答えるとインデックスを作成する (:create で指定したコマンドラインを呼び出すだけ)
;;;
;;;  M-x hyperestraier-update-index
;;;
;;;    種別を聞いてくるので、答えるとインデックスを作成する (:search で指定したコマンドラインを呼び出すだけ)
;;;
;;;  M-x hyperestraier-search
;;;
;;;    種別、検索フレーズ、結果の表示方法を指定して検索する (:index で指定した場所のインデックスを検索する)
;;;
;;; [ToDo]
;;;
;;;   * 検索結果バッファ用のモードを用意する (考えてるのは↓のような簡易的なもの)
;;;     p: 前の検索結果へ
;;;     n: 次の検索結果へ
;;;     v: 検索結果のファイルを開く
;;;   * Mew との連係
;;; 

(defvar hyperestraier-config nil)
(setq hyperestraier-config
  '((:linux
     (:howm
      (:index "/home/lambda/nobackup/casket/howm")
      (:create "estcmd create -attr @title seq -attr @author str -attr @cdate num /home/lambda/nobackup/casket/howm"
               "find  /home/lambda/howm -type f -name \"*.howm\" |estcmd gather -cl -il ja -fx .howm T@estxfilt -sd -cm /home/lambda/nobackup/casket/howm -"
               "estcmd optimize /home/lambda/nobackup/casket/howm"))
     (:mew
      (:index "/home/lambda/nobackup/casket/mew")
      (:create "estcmd create -attr @title seq -attr @author str -attr @cdate num /home/lambda/nobackup/casket/mew"
               "find  /home/lambda/Mail -type f -name \"[0-9][0-9]*\" |grep \"/[0-9][0-9]*$\" |grep -v draft |estcmd gather -pc CP932 -cl -il ja -fm -cm /home/lambda/nobackup/casket/mew -"
               "estcmd optimize /home/lambda/nobackup/casket/mew")
      (:update "find  /home/lambda/Mail -type f -name \"[0-9][0-9]*\" |grep \"/[0-9][0-9]*$\" |grep -v draft |estcmd gather -cl -il ja -fm -cm /home/lambda/nobackup/casket/mew -")))
    (:win32
     (:howm
      (:index "c:\\usr\\casket\\howm")
      (:create "estcmd create -attr @title seq -attr @author str -attr @cdate num c:\\usr\\casket\\howm"
               "c:\\cygwin\\bin\\find  c:/home/lambda/howm -type f -name \"*.howm\" |estcmd gather -pc CP932 -cl -il ja -ic CP932 -fx .howm T@estxfilt -sd -cm c:\\usr\\casket\\howm -"
               "estcmd optimize c:\\usr\\casket\\howm")
      (:update "c:\\cygwin\\bin\\find c:/home/lambda/howm -type f -name \"*.howm\" |estcmd gather -pc CP932 -cl -il -ja -fx .howm T@estxfilt -sd -cm c:\\usr\\casket\\howm -")
      (:optimize "estcmd optimize c:\\usr\\casket\\howm"))
     (:mew 
      (:index "c:\\usr\\casket\\mew")
      (:create "estcmd create -attr @title seq -attr @author str -attr @cdate num c:\\usr\\casket\\mew"
               "c:\\cygwin\\bin\\find  c:/home/lambda/Mail -type f -name \"[0-9][0-9]*\" |c:\\cygwin\\bin\\grep \"/[0-9][0-9]*$\" |c:\\cygwin\\bin\\grep -v draft |estcmd gather -pc CP932 -cl -il ja -fm -cm c:\\usr\\casket\\mew -"
               "estcmd optimize c:\\usr\\casket\\mew")
      (:update "c:\\cygwin\\bin\\find  c:/home/lambda/Mail -type f -name \"[0-9][0-9]*\" |c:\\cygwin\\bin\\grep \"/[0-9][0-9]*$\" |c:\\cygwin\\bin\\grep -v draft |estcmd gather -pc CP932 -cl -il ja -fm -cm c:\\usr\\casket\\mew -")))))

(defvar hyperestraier-buffer-name " *Hyper Estraier Command*")
(defvar hyperestraier-serach-buffer-name "*Hyper Estraier Search*")
(defvar hyperestraier-process-name "Hyper Estraier Process")
(defvar hyperestraier-temporary-file nil)

(defun hyperestraier-search-words (index pharse &optional full-p)
  (if (get-process hyperestraier-process-name)
      (message "Another process is running ...")
    (let ((buf (get-buffer-create hyperestraier-buffer-name)))
      (set-buffer buf)
      (erase-buffer)
      (let ((cfg (case (hyperestraier-check-platform)
                   (:win32 '("CP932" shift_jis-dos))
                   (t      '("EUC-JP" euc-jp)))))
        (start-process hyperestraier-process-name buf "estcmd" "search" "-ic" (car cfg) (if full-p "-vf" "-vh") "-max" "100" index (encode-coding-string pharse 'shift_jis-dos))
      (set-process-coding-system (get-process hyperestraier-process-name) 'utf-8-unix (cadr cfg)))
      (set-process-sentinel (get-process hyperestraier-process-name) 'hyperestraier-search-sentinel))))

(defun hyperestraier-search-sentinel (process event)
  (let ((buf (get-buffer-create hyperestraier-buffer-name)))
    (switch-to-buffer buf)
    (when (equal event "finished\n")
      (goto-char (point-min)))))

(defun hyperestraier-check-platform ()
  (let ((vstr (emacs-version)))
    (cond ((string-match "nt5" vstr) :win32)
          (t :linux))))

(defun hyperestraier-get-config (key)
  (let ((platform (hyperestraier-check-platform)))
    (assoc key (assoc platform hyperestraier-config))))

(defun hyperestraier-sentinel (process event)
  (let ((buf (get-buffer-create hyperestraier-buffer-name)))
    (switch-to-buffer buf)
    (goto-char (point-max))
    ;; (insert (format "Process: %s (%s) Event: %s (%s)\n" process (type-of process) event (type-of event)))
    ;;; => Process: Hyper Estraier Process (process) Event: finished\n (string)
    (when (and hyperestraier-temporary-file (equal event "finished\n"))
      (let ((memo hyperestraier-temporary-file))
        (delete-file hyperestraier-temporary-file)
        (setq hyperestraier-temporary-file nil)
        (insert (format "Delete Temporary File: %s\n" memo))))))

(defun hyperestraier-estcmd (prompt type)
  (if (or (get-process hyperestraier-process-name) hyperestraier-temporary-file)
      (message "Another process is running ...")
    (let* ((buf    (get-buffer-create hyperestraier-buffer-name))
           (keystr (completing-read prompt (cdr (assoc (hyperestraier-check-platform) hyperestraier-config)) nil t))
           (key    (intern keystr))
           (config (hyperestraier-get-config key))
           (cmdlst (cdr (assoc type config)))
           (file   (concat (or (getenv "TEMP") "/tmp/") (make-temp-name "el-he-") ".bat")))
      (when keystr
        (setq hyperestraier-temporary-file file)
        (with-temp-buffer
          (when (eq (hyperestraier-check-platform) :win32)
            (set-buffer-file-coding-system 'shift_jis-dos))
          (dolist (cmd cmdlst)
            (insert cmd)
            (insert "\n"))
          (write-region (point-min) (point-max) file))
        (switch-to-buffer buf)
        (erase-buffer)
        (let ((shell (case (hyperestraier-check-platform)
                       (:win32
                        (set-buffer-file-coding-system 'utf-8-dos)
                        file)
                       (t "sh"))))
          (start-process-shell-command hyperestraier-process-name hyperestraier-buffer-name shell file))
        (set-process-sentinel (get-process hyperestraier-process-name) 'hyperestraier-sentinel)))))

;;; 標準 API

(defun hyperestraier-make-index ()
  (interactive)
  (hyperestraier-estcmd "Hyper Estraier Create Index: " :create))

(defun hyperestraier-update-index ()
  (interactive)
  (hyperestraier-estcmd "Hyper Estraier Update Index: " :update))


(defun hyperestraier-search ()
  (interactive)
  (let* ((config (cdr (assoc (hyperestraier-check-platform) hyperestraier-config)))
         (keystr (if (> (length config) 0)
                     (completing-read "Index: " config nil t)
                   (symbol-name (caar config))))
         (key    (intern keystr))
         (config (hyperestraier-get-config key))
         (phrase (read-from-minibuffer "Search: " "" nil nil t nil))
         (index  (cadr (assoc :index config))))
    (when (and (file-directory-p index) phrase)
      (hyperestraier-search-words index phrase (yes-or-no-p "Full? ")))))

;;; サンプル

(defun he-howm-search (pharse)
  (interactive "sSearch: ")
  (let* ((config (hyperestraier-get-config :howm))
         (index  (cadr (assoc :index config))))
    (hyperestraier-search-words index pharse nil)))

(defun he-mew-search (pharse)
  (interactive "sSearch: ")
  (let* ((config (hyperestraier-get-config :mew))
         (index  (cadr (assoc :index config))))
    (hyperestraier-search-words index pharse nil)))

期待された方ごめんなさい.まだこれだけです.

しかし Hyper Estraier は速くて便利ですね.まとまった時間をとって Mew と の連携や検索画面のインターフェースなどと作りたいんですが,なかなか…. 探せばもうどっかにあるのかな?

posted: 2006/05/18 05:49 | permanent link to this entry | Tags: EMACS

(top)  (memo)  (rss)