【发布时间】:2012-01-27 17:49:58
【问题描述】:
我正在用普通的 lisp 编写计时器,输出显示在标准输出中。我想要做的是替换输出而不打印换行符,也没有并排打印,而是覆盖以前的输出,所以会有连续性的错觉。
在 common lisp 中有没有办法做到这一点?
【问题讨论】:
-
标准输出是什么?一份文件?网络连接?终端?什么样的终端?
我正在用普通的 lisp 编写计时器,输出显示在标准输出中。我想要做的是替换输出而不打印换行符,也没有并排打印,而是覆盖以前的输出,所以会有连续性的错觉。
在 common lisp 中有没有办法做到这一点?
【问题讨论】:
好的,看完了cmets,我更了解你的意图了。从你原来的问题,我假设你想替换/增加一些其他代码的输出。但现在我明白了,您真正想要的是更新屏幕。这不能仅使用基于流的 IO 来完成,您需要一些其他类型的 IO 库,例如 ncurses。
用于 ncurses 的 Common Lisp 绑定是系统 cl-charms(在 QuickLisp 中可用)。没有特定于 cl-charms 的文档,但是在 C 中使用 ncurses 的文档几乎可以不加改变地应用。这是您描述的任务的简单实现,即。它在屏幕的左上角显示(10 秒)一个时钟:
(defun clock ()
(charms:initscr)
(charms:clear)
(charms:curs-set 0)
(loop with start = (get-universal-time)
do (multiple-value-bind (s m h) (get-decoded-time)
(charms:mvaddstr 0 0 (format nil "~2,'0d:~2,'0d:~2,'0d" h m s)))
(charms:refresh)
until (>= (- (get-universal-time) start) 10))
(charms:endwin))
我遇到的两个问题:
这仅在终端中有效,在 Emacs slime-repl 缓冲区中无效。
cl-charms 无法自行找到我安装的 curses 库。它正在寻找一个名为“libcurses.so”或“libncurses.so”的库,但在我的系统上,该库仅存在版本化名称。所以我不得不在加载库期间使用USE-VALUE 重启,并为库名称列表提供替代值("libncurses.so.5")。为了经常使用该库,您可能需要更改库源代码,并向开发人员建议补丁。
从 CLiki 链接的 cl-charms 主页不可用,但 http://gitorious.org/cl-charms 的存储库可用。
下面是我在示例中使用的 ncurses/cl-charms 函数的简短说明:
initscr 初始化 ncurses。clear 清屏。curs-set 设置光标可见性,0 表示不可见。mvaddstr 将光标移动到坐标 y、x 并在那里写入一个字符串,替换之前屏幕上的内容。refresh 使对屏幕的更改实际可见。endwin 是使用完 ncurses 后调用的清理函数。
如果我正确理解您要做什么,最好的方法似乎是创建一个新的输出流类(即fundamental-character-output-stream 的子类,假设您的实现支持灰色流)。您可能应该至少为 stream-write-char 和 stream-write-string 提供专门为您的班级提供的方法。
然后您可以将带有 *standard-output* 重定义的代码包装到您的类的实例中,有点像这样:
(let ((*standard-output* (make-instance 'your-stream-class
:target *standard-output*)))
(function-to-be-called-with-wrapped-standard-output))
【讨论】:
clear 的外壳将如下所示:(sb-ext:run-program "clear" '() :search t :output t)