このログブラウザはGNU Emacsのmajor modeとして動作します。起動するに はlogview.elをload pathで指定されたディレクトリに置いておき、見たいロ グをcurrent windowとして選択した後でM-x load-library RET logview RET M-x logview RETとタイプすれば動作します。起動方法が長くてうっとおしい 場合は~/.emacsなどでautoloadするようにしておけばよいでしょう。 logview modeが実行されると、minibufferに"scanning articles..." (記事 を走査しています)という表示が出た後、"20 articles found" (20の記事が見 つかりました)というような表示になります。一方current windowには、1番 目の記事が表示されています。表示されているのは1番目の記事の部分だけで、 それ以外の行は表示されていません。カーソルを表示されている記事の外側に 移動することもできないようになっています。(これをnarrowingと呼びます) logview modeでは、以下のようなコマンドが使用できます。 キー割り当て コマンド名 説明 ==== or ======= ======================== ============================= n C-c C-n next-article 次の記事を表示します p C-c C-p previous-article 前の記事を表示します g C-c C-g goto-article 指定された記事に移動します s C-c C-s scan-articles バッファ中の記事を走査します t C-c C-t toggle-article-narrowing 記事のnarrowingをon/offします = C-c = what-article 表示中の記事番号を表示します next-article, previous-article, goto-articleの各コマンドはprefix argumentを受け付けます。next-article, previous-articleでは指定された個 数だけ次(または前)の記事に移動します。prefix argumentを指定しない場合 はそれぞれ1です。goto-articleの場合は指定された番号の記事(すなわち最 初から数えた個数の記事)に移動します。指定しない場合は現在の表示記事を 再表示します。 scan-articlesはバッファ中の記事を走査しなおします。これは記事の header/trailerのパターンを定義しなおした場合などに有効です。 toggle-article-narrowingは記事のnarrowingをon/offします。通常は表示 記事以外のものは画面には現れないようになっていますが、narrowingをoffに すると該当記事の前後の行も表示され、カーソルの移動等もできるようになり ます。表示記事の移動はnarrowingが有効な時と同じように行われます。 what-articleでは、現在表示中の記事が何番目のものなのかをminibufferに 表示します。 加えて、カーソル移動のような通常のコマンドも使用することができます。 ただし、logview-mode実行直後にカレント・バッファはreadonlyに設定される ためバッファの内容を変更するようなコマンドは使用できません。(勿論、 toggle-read-onlyを実行すればバッファの内容を変更することができますが、 この後、記事の表示が正しく行われなくなります。このような場合は scan-articlesを再実行して下さい) logview modeでは、ユーザがいくらかのカスタマイズを行うことができます。 カスタマイズを行う場合は、 (setq logview-mode-hook (function (lambda () : :))) という「おまじない」を~/.emacsに書きます。この中の .... の部分に カスタマイズしたい項目を記入します。 logview modeはデフォルトではNIFTY Serveの記事を検出するようになって いますが、他のBBS用にカスタマイズすることも可能です。それには以下のよ うな記述をmode-hookに入れます。 ;; 記事の先頭となる行の正規表現のリスト (setq header-regexp-list '("^BBS [0-9]+/[0-9]+" "^SIG [0-9].* [0-9]+/[0-9]" "^COM [0-9].* [0-9]+/[0-9]" "^Note [0-9]+/[0-9]+")) ;; 記事の終りとなる正規表現のリスト (setq trailer-regexp-list '("^End of : " "^SIG :" "^COM :" "^Notes cmd:")) また、 (setq do-narrowing-article nil) を追加すると、デフォルトでは記事のnarrowingを行わなくなります。 (logview-mode実行後にtoggle-article-narrowingでnarrowingのon/offをする ことはこの場合も可能です)キーバインドを変更する場合には、define-keyを 使用します。例えばnext-articleをControl-Nにしたい場合は、 (define-key logview-mode-map "\C-n" 'next-article) とします。 以上でlogview.elの説明を終ります。これを読んでお分かりのように、まだ 本当に基本的な機能しかサポートしていません。いかんせん、ログブラウザと いうものをあまり見たことがないので、今後どういう機能をつければよいのか わかりません。よいアイデアがあれば教えていただきたいです。現在kermitを 使用してBBSの自動アクセスを行っているので、それと組み合わせてRES付けな どが快適にできるようになるといいなとは思っています。 しかしLispってやっぱり強力な言語ですね。こういうのが150行くらい (しかもコメント込み)で書けてしまうのですから。また、プログラムの作成は ほとんどLisp Interaction modeのみで行いましたが、快適にコーディングを 行うことができました。 ---- 川俣/新潟市 ====================================================================== ;;; Testing some elisp codes -*- lisp-interaction -*- ;;; logview.el --- simple viewer for BBS log files ;;; Code: (defvar logview-mode-map nil "local key map for logview mode") (if logview-mode-map nil (setq logview-mode-map (make-sparse-keymap)) (define-key logview-mode-map "s" 'scan-articles) (define-key logview-mode-map "g" 'goto-article) (define-key logview-mode-map "n" 'next-article) (define-key logview-mode-map "p" 'previous-article) (define-key logview-mode-map "t" 'toggle-article-narrowing) (define-key logview-mode-map "=" 'what-article) (define-key logview-mode-map " " 'scroll-up) (define-key logview-mode-map "b" 'scroll-down) (define-key logview-mode-map "l" 'recenter)) (defvar header-regexp-list '("^[0-9]+/[0-9]+ +[A-Z][A-Z][A-Z][0-9][0-9][0-9][0-9][0-9] +.+$") "List which contains regexps representing article header") (defvar trailer-regexp-list '("^>[ -~]+$" "^- F[0-9A-Z]+ +MES") "List which contains regexps representing article trailer") (defvar current-article-number 1 "viewing article number") (defvar do-narrowing-article t "if non-nil, narrowing current article") (defun search-regexps (regexp-list val) (let ((retval nil)) (mapcar (function (lambda (regexp) (goto-char (point-min)) (while (re-search-forward regexp (point-max) t) (setq retval (cons (list (match-beginning 0) val) retval))))) regexp-list) retval)) (defun make-region (l) (let ((rest l) (retval nil)) (while rest (if (equal (car (cdr (car rest))) t) (setq retval (cons (cons (car (car rest)) (list (if (cdr rest) (car (car (cdr rest))) (point-max)))) retval))) (setq rest (cdr rest))) (reverse retval))) (defun scan-articles () "Scanning thru current buffer to find article header/trailer, then build article regions list." (interactive) (save-excursion (widen) (message "scanning articles...") (setq article-regions-list (make-region (sort (append (search-regexps header-regexp-list t) (search-regexps trailer-regexp-list nil)) (function (lambda (a b) (< (car a) (car b))))))) (message "%d articles found." (length article-regions-list)))) (defun goto-article (n) "go to N-th article passed by prefix arg. if prefix arg. not given, recenter current article." (interactive "P") (let ((goto-article-number (if (null n) current-article-number (if (consp n) (car n) n)))) (if (null article-regions-list) (message "no articles to go") (cond ((<= goto-article-number 1) (setq current-article-number 1) (message "beginning of article")) ((<= (length article-regions-list) goto-article-number) (setq current-article-number (length article-regions-list)) (message "end of article")) (t (setq current-article-number goto-article-number))) (widen) (goto-char (car (nth (1- current-article-number) article-regions-list))) (recenter 0) (and do-narrowing-article (apply (function narrow-to-region) (nth (1- current-article-number) article-regions-list)))))) (defun next-article (n) "move next N-articles passed by prefix arg." (interactive "p") (goto-article (+ current-article-number n))) (defun previous-article (n) "move previous N-articles passed by prefix arg." (interactive "p") (goto-article (- current-article-number n))) (defun toggle-article-narrowing () "toggle narrowring displaying article or not." (interactive) (setq do-narrowing-article (not do-narrowing-article)) (if do-narrowing-article (goto-article current-article-number) (widen))) (defun what-article () "print current article number in minibuffer." (interactive) (message "article (%d/%d)" current-article-number (length article-regions-list))) (defun logview-mode () "viewing BBS logfile mode \\{logview-mode-map}" (interactive) (kill-all-local-variables) (make-local-variable 'header-regexp-list) (make-local-variable 'trailer-regexp-list) (make-local-variable 'current-article-number) (setq current-article-number 1) (make-local-variable 'do-narrowing-article) (make-local-variable 'article-regions-list) (setq article-regions-list nil) (setq major-mode 'logview-mode) (setq mode-name "LogView") (use-local-map logview-mode-map) (setq buffer-read-only t) (run-hooks 'logview-mode-hook) (scan-articles) (sit-for 2) (goto-article 1)) ======================================================================