一个晦涩难解的问题:已记录的VT100“软包装”转义序列?

埃文斯

当通过SSH(终端类型设置为vt100)通过SSH连接到远程BASH会话时,当光标到达第80列时,控制台命令行将自动换行。

我想发现的是<space><carriage return>,此时发送序列是否记录在任何地方?

例如发送以下字符串

    std::string str = "0123456789"  // 1
                        "0123456789"
                        "0123456789"    // 3
                        "0123456789"
                        "0123456789"    // 5
                        "012345678 9"
                        "0123456789_"   // 7
                        "0123456789"
                        "0";

从主机获取以下响应(发生情况时为Linux Mint)

01234567890123456789012345678901234567890123456789012345678<WS><WS><CR>90123456789_01234567890

观察到的行为并不是bash真正的一部分;相反,它是readline行为的一部分如果仅使用echo(这是内置的bash)输出足够的文本以强制自动换行,就不会发生这种情况,如果bash产生的错误消息比控制台还宽,则不会发生这种情况。(例如,尝试.使用参数超过80个字符的命令,而不与任何现有文件相对应。)

因此,这不是官方的“软包装序列”,也不是任何标准的一部分。而是,它是与控制台显示管理相关的许多烦人问题之一的实用解决方案。

换行的终端实现中存在歧义:

  1. 在最右边的位置插入一个字符后,终端将自动换行。

  2. 终端在发送下一个字符之前自动换行。

结果,不可能在最后一列位置之后可靠地发送换行符。如果终端已经换行(上面的选项1),那么换行符将创建一个额外的空白行。否则(选项2),以下换行符将被“吃掉”。

如今,几乎所有终端都遵循选项2的某些变体,即DEC VT-100终端的行为。terminfo终端描述数据库的词汇表中,这称为xenl:“ eat-newline-glitch”。

选项2实际上有两个可能的子变量。在VT-100(和xterm)实际实现的一个变量中,游标在行的结尾处以异常状态结束;实际上,它是屏幕外一个字符的位置,因此您仍然可以在同一行中退格光标。其他历史终端“吃”了换行符,但是无论如何都将光标定位在下一行的开头,因此将不能使用退格键。(除非终端具备此bw功能。)

这给需要精确跟踪光标位置的程序带来了一个问题,即使对于诸如回显输入之类的简单应用程序也是如此。(显然,回显输入的最简单方法是让终端自行执行此操作,但这排除了能够实现诸如制表符补全之类的额外控制字符的可能性。)假设用户已经输入了右上角的文本,然后键入退格字符以删除最后键入的字符。通常,您可以通过输出cub1(向左移动1)代码然后输出el(清除到行尾)代码来实现退格删除(如果删除在行的中间会更复杂,但是原理是相同的。)

但是,如果光标可能位于下一行的开头,则此操作将无效。如果您知道光标位于下一个光标的开始,则可以先向上然后向右移动,然后再执行el,但是如果光标仍在同一行上,则该操作将无效。

从历史上看,被认为是“正确”的是用硬返回将光标强制到下一行。(以下引用来自分发中terminfo.src找到的文件ncurses。我不知道是谁写的,什么时候写的):

# Note that the <xenl> glitch in vt100 is not quite the same as on the Concept,
# since the cursor is left in a different position while in the
# weird state (concept at beginning of next line, vt100 at end
# of this line) so all versions of vi before 3.7 don't handle
# <xenl> right on vt100. The correct way to handle <xenl> is when
# you output the char in column 80, immediately output CR LF
# and then assume you are in column 1 of the next line. If <xenl>
# is on, am should be on too.

但是还有另一种方法可以解决该问题,甚至不需要您知道终端是否有xenl“毛刺”:输出一个空格字符,此后终端肯定会换行,然后返回到最左列。

事实证明,如果终端仿真器是xterm(可能还有其他类似的仿真器),则该技巧还有另一个好处,即允许您通过双击选择“单词”。如果自动换行发生在单词的中间,那么即使您将整个单词分为两行,仍然可以选择整个单词,这将是理想的选择。如果您遵循terminfo上面文件中的建议,那么xterm(相当合理)会将拆分词视为两个词,因为它们之间有一个明确的换行符。但是,如果让终端自动换行,xterm则将结果视为一个单词。(尽管输出了空格字符,但仍会这样做,可能是因为空格字符已被覆盖。)

简而言之,该SPCR序列绝不是VT100终端的标准功能。相反,它是对终端描述的特定功能与特定(和通用)终端仿真器的观察到的行为的实用响应。可以在各种代码库中找到该代码的变体,尽管据我所知,它不是任何教科书或正式文档的一部分,但它无疑是终端处理民俗的一部分[注2]。

在的情况下readline,您会在代码中找到一条注释,该注释比此答案更具电报性:[注释1]

  /* If we're at the right edge of a terminal that supports xn, we're
     ready to wrap around, so do so.  This fixes problems with knowing
     the exact cursor position and cut-and-paste with certain terminal
     emulators.  In this calculation, TEMP is the physical screen
     position of the cursor. */

xn是的缩写xenl。)


笔记

  1. 当我键入此答案时,注释位于资源库display.c当前视图中的第1326行git在将来的版本中,它可能位于不同的行号,因此提供的链接将不起作用。如果您发现它已更改,请随时更正链接。

  2. 在此答案的原始版本中,我将此过程描述为“终端处理民俗学的一部分”,在该过程中,我使用“民俗学”一词来描述从程序员传给程序员的知识,而不是成为学术教科书的一部分。国际标准。尽管“民俗学”经常带有否定含义,但我在没有这种偏见的情况下使用它。“知识”(根据维基百科)是指“随着时间的流逝,通过教育或经验积累的关于特定主题的所有事实和传统”,源于古日耳曼语单词,意思是“教学”。因此,民俗是“民俗”的积累的教育和经验,而不是建立:在埃里克·雷蒙德(Eric S. Raymond),民间文学艺术是集市的知识基础。

    这种用法引起了至少一位高技能从业者的注意,他们建议使用“深奥的”一词来描述有关终端处理的信息。“神秘的”(再次根据维基词典的说法)适用于“预期仅由少数具有专业知识或兴趣的人或可能被内在圈子启发的人理解或理解的信息”,该信息源自希腊语ἐσωτερικός,“内部圈”。(换句话说,就是大教堂的知识。)

    尽管语义讨论至少很有趣,但我还是使用了希望减少感情的词“民间工艺”来更改了文本。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章