Python + readline + auto-completion(tab):为什么破折号和问号被视为单词分隔符?

时间:2011-09-22 17:11:04

标签: python gnu readline python-2.7

Hello编码员和勇敢的GNU-readline用户,
几个月前,我开始使用Python的(2.7.1)readline模块来编写我编写的类似shell的应用程序。该应用程序与文件和文件系统无关 - 它是专有管理软件的定制解决方案。

昨天我发现特定文本会导致意外的自动完成行为,并且找不到在documentation中解决此问题的方法。我在这里拼命地请求你的帮助。我将从一个示例开始,然后使用一个代码片段来重现不需要的行为。

提供自动完成的值为:

aaa0   aaa1   aaa2   bbb_0  bbb_1  bbb_2
ccc-0  ccc-1  ccc-2  ddd?0  ddd?1  ddd?2

...然后意外行为如下(每个动作后跟结果输出,管道符号代表光标):

  1. 输入'b'。
    Input> b|
  2. 按TAB键(在我的配置中绑定到自动完成操作) Input> bbb_|
  3. 再次按TAB键。您的文字将保持不变,但您会收到以下提示:
    bbb_0 bbb_1 bbb_2
    Input> bbb_|
  4. 输入“0”并按TAB键 bbb_0 bbb_1 bbb_2
    Input> bbb_0 |

    注意'0'字符和光标之间的空格(下面的代码片段将解释这一点) 到目前为止一直这么好,尝试使用'a'会产生类似的输出,只有没有下划线(aaa0,aaa1,aaa2)。
  5. 重新开始并输入'c' Input> c
  6. 按TAB键 Input> ccc-
  7. 再次按Tab键 aaa0 aaa1 aaa2 bbb_0 bbb_1 bbb_2 ccc-0 ccc-1 ccc-2 ddd?0 ddd?1 ddd?2
    Input> ccc-|

    这是我问题的前半部分。显示所有值,而不是仅显示以'ccc - '开头的值。
  8. 键入“0”,然后按Tab键 aaa0 aaa1 aaa2 bbb_0 bbb_1 bbb_2 ccc-0 ccc-1 ccc-2 ddd?0 ddd?1 ddd?2
    Input> ccc-0|

    这是我问题的后半部分,你看,'0'字符和光标之间没有空格(同样,下面的代码片段将解释为什么应该有空格)。事实上,按下TAB既没有改变文本也没有显示提示,而且进一步的TAB按键表现相同。
  9. 在实践中,步骤7中发生的是误解。 Readline“错误”字符分隔符的' - '字符(对于问号'?'字符也是如此,如果你尝试自动完成'ddd?';其他常见字分隔符是,例如:空格,制表符,'=')。因此,由于当前行缓冲区以字分隔符结束,那么是时候换个新单词吧?因此,在步骤7(我们所处的位置),按TAB键显示所有值。

    在步骤8中,一旦该行看起来像这个“Input> ccc-0|”,按TAB就没有效果,因为短划线是一个单词分隔符,将该行分成两个单词:'ccc'和'0 ”。所以,要完成的单词是'0',但是唉,没有一个可能的值以'0'开头,所以没有效果。

    现在,遗憾的是,这里没有对错。例如,在我的应用程序中,等号'='实际上 是一个单词分隔符,但短划线' - '不是。 我认为这必须是配置问题,但我还没有找到一种方法来配置哪些字符分隔单词。这就是我需要帮助的地方。

    我是一个忠诚的人,所以这是我承诺的代码片段:

    import readline
    values = ['aaa0',  'aaa1',  'aaa2',  'bbb_0', 'bbb_1', 'bbb_2',
              'ccc-0', 'ccc-1', 'ccc-2', 'ddd?0', 'ddd?1', 'ddd?2']
    def complete(text, state):
        matches = [v for v in values if v.startswith(text)]
        if len(matches) == 1 and matches[0] == text:
            # Add space if the current text is the same as the only match
            return "{} ".format(matches[0]) if state == 0 else None
        if state >= len(matches):
            return None
        return matches[state]
    readline.set_completer(complete)
    for line in ("tab: complete", "set show-all-if-unmodified on"):
        readline.parse_and_bind(line)
    raw_input("Input> ")
    

    男孩和女孩,请 - 帮忙!我保证会非常感激,甚至会回报。的

    非常感谢, Amnon G

1 个答案:

答案 0 :(得分:5)

仅查看dir(readline)的输出,函数get_completer_delims()set_completer_delims()看起来可能很有用。实际上,readline模块的文档包括:

set_completer_delims(...)
    set_completer_delims(string) -> None
    set the readline word delimiters for tab-completion

我认为这完全描述了你想要的东西。这是在Python 2.6.7上;如果您之前正在运行某些功能,则可能无法使用此功能。