テキストブラウザ #6
2007/08/27
前回(id:smeghead:20070825:ncurses2)の続き
ファイヤープロジェクト
ここのサイトのの情報って幅広さと濃さが凄いですね。かなり前から色々な言語でお世話になっています。
matsuさんという方が個人で作成しているらしいです。頭が下がりますm(_ _)m
パッド
パッドを使用すると論理画面にまとめて表示データを格納しておいて,必要な分だけ物理画面で表示することが可能になる.しかも簡単に.
http://www.fireproject.jp/feature/c-language/curses/pad.html#2
以前、仮想画面と勘違いしていたのはパッドでした。ということでパッドを試してみました。
今回は、上のサイトで紹介されている「なんちゃってless」をcommon lispで書いてみました。
- オリジナルのなんちゃってlessから変更した点
- w3mのようにカーソルがある点
- キーバインドをw3m風に(といってもhjklqしか作ってません)
curses-wrapper.lisp
継ぎ接ぎだらけですがここに置いてみました。
追加したマクロ
(defmacro with-pad (pad-name initial-proc &body body) `(progn (setq ,pad-name ,initial-proc) ,@body (delwin ,pad-name)))
less.lisp
(load "/usr/lib/clisp/asdf.lisp") (setf asdf:*central-registry* '(*default-pathname-defaults* #p"/usr/lib/clisp/system/")) (asdf:oos 'asdf:load-op :cffi :verbose nil) (load "curses-wrapper.lisp") (use-package :curses-wrapper) (defun get-contents (file-name) (with-open-file (stream file-name :direction :input) (loop for line = (read-line stream nil 'eof) until (equal line 'eof) collect line))) (defun setup-pad (contents) (let ((pad-y 0) (pad-x 0)) (loop for line in contents for i from 0 do (mvwprintw *stdpad* i 0 line)) (defun pad-down () (if (and (eql (getcury *stdscr*) (1- *LINES*)) (< (+ pad-y *LINES*) (getmaxy *stdpad*))) (prefresh *stdpad* (incf pad-y) pad-x 0 0 (1- *LINES*) (1- *COLS*)) (wmove *stdscr* (1+ (getcury *stdscr*)) (getcurx *stdscr*)))) (defun pad-up () (if (and (eql (getcury *stdscr*) 0) (> pad-y 0)) (prefresh *stdpad* (decf pad-y) pad-x 0 0 (1- *LINES*) (1- *COLS*)) (wmove *stdscr* (1- (getcury *stdscr*)) (getcurx *stdscr*)))) (defun pad-left () (if (and (eql (getcurx *stdscr*) 0) (> pad-x 0)) (prefresh *stdpad* pad-y (decf pad-x) 0 0 (1- *LINES*) (1- *COLS*)) (wmove *stdscr* (getcury *stdscr*) (1- (getcurx *stdscr*))))) (defun pad-right () (if (and (eql (getcurx *stdscr*) (1- *COLS*)) (< (+ pad-x *COLS*) (getmaxx *stdpad*))) (prefresh *stdpad* pad-y (incf pad-x) 0 0 (1- *LINES*) (1- *COLS*)) (wmove *stdscr* (getcury *stdscr*) (1+ (getcurx *stdscr*))))))) (defun main (args) (if (not args) (format *error-output* "Usage: clisp less.lisp filename~%") (progn (let ((contents (get-contents (car args)))) (with-curses (cbreak) (noecho) (scrollok *stdscr* FALSE) (with-pad *stdpad* (newpad (length contents) (loop for line in contents maximize (length line))) (setup-pad contents) (refresh) (prefresh *stdpad* 0 0 0 0 (1- *LINES*) (1- *COLS*)) (input-loop key (((char-code #\q) (char-code #\Q)) (return)) ((char-code #\h) (pad-left)) ((char-code #\j) (pad-down)) ((char-code #\k) (pad-up)) ((char-code #\l) (pad-right))))))))) (main *args*)
いろいろ試すいい機会なので、マクロとかクロージャも積極的に使う方向でやってみています。
でも大域変数使いすぎで汚ないです;;ncursesプログラミングはこんなもんなのかな?
実行方法
$ clisp less.lisp <text file name>
感想
パッドは便利。