已关闭,此问题需要details or clarity。它目前不接受回答。
**想改善这个问题吗?**通过editing this post添加详细信息并澄清问题。
7年前关闭。
Improve this question
作为更好地理解我的计算机的练习和工具,我用C++编写了my own shell。Stephen Brennan's article on writing a simple shell非常有用。
然而,让我困惑的是如何处理按下向上箭头和向下箭头来滚动我的命令历史。
- 我尝试了
ncurses
,但它取代了整个屏幕,而系统提供的shell似乎只是继续写入终端。 - 我尝试使用
tcgetattr
来关闭规范模式,但虽然这让我在键入时按下箭头键,但它也关闭了用于文本导航的左/右箭头键的所有处理,以及退格键和Ctrl-C.虽然我可以自己发送一个信号来响应Ctr-C,但我不知道如何让终端将光标移回(除了输出一个“return”和重写行的开头)。它似乎也给了我给予不同的键转义序列,这取决于我是在Xcode的“哑”终端还是在我的Mac的Terminal. app中运行。 - 我查看了
fish
Shell和bash
的源代码,但似乎有太多的东西,我找不到相关的部分。
标准shell如何处理接收按键?他们如何处理移动光标和退格键?他们如何重写一行的一部分,而不必接管屏幕?有没有一个标准来定义shell需要做什么?
PS -我知道如何记录以前的命令。这是实际上得到按键,而他们正在输入,而不是在有人按下返回,我不能去工作。
1条答案
按热度按时间lokaqttq1#
你必须关闭
ICANON
和ECHO
,并自己解释箭头键的转义序列。你必须保持你自己的“实际”缓冲区的什么在屏幕上和光标在哪里。您还需要一个“所需”的缓冲区,您想要在屏幕上的东西和您想要的光标。这些缓冲区不会覆盖整个屏幕,只覆盖包含提示符和用户输入的行(由于关闭了
ECHO
,因此手动回显)。既然你把所有的东西都印在这几行上,你就知道它们的内容了。就在等待下一个输入字节之前,更新屏幕以匹配所需的缓冲区。当您使用300(甚至9600)波特的连接时,您非常关心如何通过寻找可打印字节和终端控制序列的最佳序列来将实际缓冲区转换为所需的缓冲区,从而使更新尽可能高效。如今,最佳状态已经不那么重要了。
如果输入换行,这些缓冲区将跨行,因此您需要知道并跟踪终端宽度(使用
TIOCGWINSZ
和SIGWINCH
)。您可以使用水平滚动而不是换行来坚持单行,但您仍然需要知道终端宽度。理论上,您可以在termcap或terminfo数据库中查找您的终端类型(从
$TERM
)。它告诉你当用户按下特殊键(箭头键、home键、end键等)时会有什么样的转义序列,以及要发送什么样的转义序列来移动光标、清除屏幕的某些部分、插入或删除字符或行等。如今,假设所有东西都与xterm兼容是相当安全的,特别是对于业余爱好项目。
对于bash,这一切都在GNU readline库中完成。更新屏幕(称为“重新显示”)在
display.c
中完成。输入转义解码在input.c
中完成。但是,如果你想要示例代码,你可能应该看看linenoise,它不到2000行。它假设终端兼容VT 100(因此也兼容xterm)。
参见“Is there a simple alternative to Readline?”