使用 GNU 阅读线;如何在同一程序中添加 ncurses?

Posted

技术标签:

【中文标题】使用 GNU 阅读线;如何在同一程序中添加 ncurses?【英文标题】:Using GNU Readline; how can I add ncurses in the same program? 【发布时间】:2010-10-16 01:17:13 【问题描述】:

标题比我的实际目标更具体一点:

我有一个使用 GNU Readline 的命令行程序,主要用于命令历史记录(即使用向上箭头检索以前的命令)和其他一些细节。现在程序的输出似乎与用户的输入穿插在一起,这有时是可以的,但输出是异步的(它通过网络连接来响应输入命令),有时会变得烦人(例如,如果在用户输入时输出行正在输入新的输入)。

我想为这个程序添加一个功能:一个单独的输出“窗口”。我考虑过为此使用ncurses。但是从ncurses FAQ看来,这两个库不好一起用。

我可能会考虑使用 Editline 或 tecla 代替 Readline,但我不清楚这两种方法是否能解决我的问题。我还考虑使用 ncurses 以外的东西,包括提供两种功能(文本模式窗口和命令历史记录)的库,但我不知道什么可能是最好的。

哦,对彩色文本的支持可能会获得奖励积分。我怀疑我可以用 Readline 做到这一点,所以也许这是一个单独的问题,但如果我的问题的解决方案也可以很容易地为输出添加一些颜色,那就更好了。

我使用的是 Ubuntu Hardy (Linux 2.6)。

【问题讨论】:

我放弃了(并坚持使用 readline)。 【参考方案1】:

我现在在 GitHub 上整理了一个简单的示例程序:https://github.com/ulfalizer/readline-and-ncurses。

它支持无缝和高效的终端调整大小和多字节/组合/宽字符。该代码有有用的 cmets。

截图如下:

【讨论】:

太棒了!什么是代码许可证?如果可能的话,我想将它与一些 MIT 许可的材料集成。谢谢! 很高兴它有帮助!如果麻烦最少的话,我可以把它放在麻省理工学院。否则我会选择 ISC,麻省理工学院看起来很相似。顺便说一下,对于github.com/ulfalizer/botniklas,我还有一个版本可以运行 select() 循环(或在本例中为 epoll())。跑题了,还没推,但如果你有兴趣,我可以为它做一个分支。 该版本安装了一个 SIGWINCH 处理程序(尽管使用 signalfd() 而不是普通处理程序)并让 readline 直接从标准输入读取。这也恰好解决了搜索和多字节字符的问题。 这很好,但在OS X El CapitanTerminal 上不支持滚动功能。相反,它会滚动readline 的历史记录。也许与此有关:macissues.com/2014/06/10/… @Adam:没有滚动功能。添加顶部窗口只是为了获得更有趣的布局,并在示例中对来自 readline 的输入进行实际操作。【参考方案2】:

我做了一些搜索,看来你运气不好。

对于 ncurses 替代品,有 SLang、Newt 和 Turbo Vision。俚语不仅仅是屏幕处理,因此更多 复杂,但也许它可以用于您的目的?纽特使用屏幕 处理和更简单,但过于简单和单线程模式 我认为是为了你的目的。

Turbo vision 是 Borland 的文本模式图形库,由 他们在 80 年代末/90 年代初的所有工具。 Borland 公布了源码 当这种东西的市场减少时编写代码,并且有 现在是 linux 的一个端口(旁注,this project 似乎已经写了 它自己的 turbo vision 实现)。那个端口没有死(有 今年有一些 cvs 更新编译得很好(旧版本 没有)),但我发现的电视示例都不是最新的,我 在放弃其余部分之前,确实只编译了其中的一些。 这有点可惜,因为电视是一个可爱的使用环境。 电视是 Btw C++(我假设您使用的是 C?)。

对于 readline 的替代方案,有 libkinput,它可能有效 与 ncurses 一起(它说它可以使用 ncurses 的 terminfo。但我是 不确定这是否意味着它可以与 ncurses 使用共存)?

也许一种选择是在您的 ncurses 程序“外部”运行 readline 使用rlwrap?

【讨论】:

俚语本身就是一种语言。此外,它仅适用于最新版本的 GPL2 许可证。我期待它是一个图书馆。 请注意,Newt 是 SLang 之上的一个层。它可能更容易使用,但它完全是另一种选择。【参考方案3】:

这让我头疼了几个小时,所以只是为了让人们在谷歌上搜索一些痛苦:

如果您使用 ncurses 的内置 SIGWINCH 处理程序和 KEY_RESIZE,请注意 readline 默认设置 LINESCOLUMNS 环境变量。这些会覆盖 ncurses 否则会执行的任何动态大小计算(通常使用 ioctl() TIOCGWINSZ),这意味着即使在调整终端大小后您仍将继续获得初始终端大小。

这可以通过在初始化 readline 之前将rl_change_environment 设置为0 来防止。

更新:

以下是我从 readline 资源中收集到的一些额外信息:

readline 的 SIGWINCH 处理代码(如果 rl_catch_sigwinch 为 1 时使用)确实更新了 LINESCOLUMNS,这对于 ncurses 来说似乎已经足够了。但是,当使用备用 readline 接口时(将 readline 与 ncurses 结合使用时最有意义),信号处理程序(包括SIGWINCH 的处理程序)将仅在每个rl_callback_read_char() 调用期间安装,这意味着任何终端调整大小在两次调用rl_callback_read_char() 之间,readline 不会看到。

【讨论】:

请考虑formatting您的答案。命令/代码难以阅读。【参考方案4】:

所以事实证明 gdb 同时使用了 readline 和 ncurses。如果您有兴趣这样做,我建议您查看他们的实现:http://sourceware.org/git/?p=gdb.git;a=blob;f=gdb/tui/tui-io.c

【讨论】:

哇,谢谢。欢迎来到 ***,纪尧姆。 :)【参考方案5】:

我已经实现了你在我的一个程序中描述的内容:

http://dpc.ucore.info/lab:xmppconsole

以下是文件处理io:

http://github.com/dpc/xmppconsole/blob/master/src/io.c

【讨论】:

【参考方案6】:

我不确定您尝试了哪个版本。截至今天(2012.09.14),很简单,我们只需要将我们自定义的函数挂钩到下面的函数指针上即可。

rl_getch_function rl_redisplay_function rl_completion_display_matches_hook

我做了一些合理的事情here。

【讨论】:

好的,我发现了。必须显示rl_display_prompt,然后是rl_line_buffer,并将光标偏移设置为rl_point + strlen(rl_display_prompt)

以上是关于使用 GNU 阅读线;如何在同一程序中添加 ncurses?的主要内容,如果未能解决你的问题,请参考以下文章

使用多线程在 GNU C 中使用写入函数是不是安全

如何在 gnu 屏幕中切换 CR/LF?

Mac终端解压:让解压更逼格

如何阅读管道分隔线 |来自一个文件并在两个不同的 ArrayList 中拆分整数

HTML5 离线缓存

GNU makefile 规则和依赖项