readline 被 ANSI 转义序列混淆

readline confused by ANSI escape sequences

我正在开发一个 Python 脚本,该脚本有时需要用户输入。我在 macOS Sierra 上使用 bash。

为了接收输入,我写了以下内容:

import readline  # gnureadline 6.3.8

START = '3[91m3[1m'
END = '3[0m'

response = raw_input(START + 'Enter text: ' + END)

我在 STARTEND 中使用 ANSI 转义序列来从视觉上区分脚本的提示和用户的文本输入。

不幸的是,一旦我开始输入文本,程序就无法跟踪用户输入文本的实际开始位置。下面的第一个克拉是 CTRLA 现在映射到的位置,第二个是 CTRL[= 的位置35=]E带我。箭头键同样认为用户输入的开始和结束是偏移的,如图所示。

Enter text: hello my name is             
                         ^               ^  

我尝试了一些调试方法。

  1. 我尝试在提示符和文本输入之间添加一个换行符,但这只会使偏移更糟。

  2. 如果我使用方向键而不是CTRLA, CTRLE, option-arrow 来浏览字符串,这按预期工作。也就是说,考虑到用户输入的字符串的长度和复杂性,仅使用箭头键在字符串中移动对用户来说会很痛苦。

  3. 最重要的是,如果我根本不使用 STARTEND,这将完美运行。也就是说,脚本的可用性下降了——很难从完整版脚本的所有其他文本中找出提示。

我有什么技巧可以使用 ANSI 转义序列来格式化提示,而不会破坏用户使用 CTRLA 进行导航的能力CTRLE 和选项箭头?谢谢!

将提示和要求输入分开打印到两个命令中。

Python 3.x

print(START + 'Enter text: ' + END, end='')
response = input()

Python 2.x

import sys

# Use sys.stdout.write to avoid printing a trailing newline.
sys.stdout.write(START + 'Enter text: ' + END)
response = raw_input()

就我而言,接受的答案没有成功。

我从

开始
START = '\x1b[7m\x1b[37m' # white on black
END = '\x1b[0m'  # reset
response = input(START + 'QUERY ' + END)

这同样导致了

QUERY hello my name is hello my name is
              ^                                ^
              hello my name is hello my name is

使用上面的解决方案,

print(START + 'QUERY ' + END, end='')
response = input()

导致它认为该行从开头开始

QUERY hello my name is hello my name is
^                                ^
hello my name is hello my name is

可能是因为 input("") 的长度为 0 个字符。

知道那些控制字符被算作偏移量,我们可以使用它们再次创建偏移量。

我的文本 QUERY 有 6 个字符,所以我可以使用

print(START + 'QUERY ' + END, end='')
response = input('3[D3[C')

因为Cursor Forward, Cursor Back '3', '[', 'D''3', '[', 'C' 正在欺骗 readline 偏移 6 个字符。

QUERY hello my name is hello my name is
\[D\[C^                                ^
      hello my name is hello my name is

Readline 期望 [=11=]1[=12=]2 作为不可见字符周围的标记:

import readline  # gnureadline 6.3.8

START = '[=10=]13[91m3[1m[=10=]2'
END = '[=10=]13[0m[=10=]2'

response = raw_input(START + 'Enter text: ' + END)

使用 ANSI 转义序列以 [=11=]1 为前缀并以 [=12=]2 为后缀,GNU readline 将知道在确定提示字符串的长度时应排除这些字符。