蟒蛇 +阅读线+自动完成(选项卡):为什么破折号和问号被视为单词分隔符?

发布于 2024-12-06 06:48:34 字数 2475 浏览 1 评论 0原文

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

昨天我发现特定的文本会导致意外的自动完成行为,并且在

提供自动完成的值为:

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

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

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

    请注意“0”字符和光标之间的空格(下面的代码片段将解释这一点)。
    到目前为止一切顺利,尝试对 'a' 进行相同的操作将得到类似的输出,只是没有下划线(aaa0、aaa1、aaa2)。
  5. 重新开始并输入“c”。
    输入> c
  6. 按 TAB 键。
    输入> ccc-
  7. 再次按 TAB 键。
    aaa0 aaa1 aaa2 bbb_0 bbb_1 bbb_2 ccc-0 ccc-1 ccc-2 ddd?0 ddd?1 ddd?2
    输入> 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
    输入> ccc-0|

    这是我的问题的后半部分,你看,“0”字符和光标之间没有空格(同样,下面的代码片段将解释为什么应该有空格)。事实上,按 TAB 既不会更改文本,也不会显示提示,并且进一步按 TAB 的行为相同。

实际上,第 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> ")

男孩女孩们,请帮忙!我保证会非常感激,甚至还以回报。

提前非常感谢, 阿姆农·G

Hello coders and brave GNU-readline users,
A few months ago I started using Python's (2.7.1) readline module for a shell-like application I've written. The application has nothing to do with files and file-systems - it's a tailored solution for proprietary management software.

Yesterday I found that specific text causes unexpected auto-completion behavior, and haven't found a way to resolve this in the documentation. I'm desperately asking for your help here. I'll start with an example, and follow with a code snippet that reproduces the unwanted behavior.

Providing the values for auto-completion are:

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

...then the unexpected behavior is as follows (each action is followed by the resulting output, and a pipe | sign represents the cursor):

  1. Type 'b'.
    Input> b|
  2. Press TAB (which in my configuration is bound to the auto-completion action).
    Input> bbb_|
  3. Press TAB again. Your text will remain the same, but you will receive the following hint:
    bbb_0 bbb_1 bbb_2
    Input> bbb_|
  4. Type '0' and press TAB.
    bbb_0 bbb_1 bbb_2
    Input> bbb_0 |

    Note the space between the '0' character and the cursor (the code snippet below shall explain this).
    So far so good, and trying the same with 'a' will result in similar output, only without an underscore (aaa0, aaa1, aaa2).
  5. Start over and type 'c'.
    Input> c
  6. Press TAB.
    Input> ccc-
  7. Press TAB again.
    aaa0 aaa1 aaa2 bbb_0 bbb_1 bbb_2 ccc-0 ccc-1 ccc-2 ddd?0 ddd?1 ddd?2
    Input> ccc-|

    This here is the first half of my problem. All values are displayed, instead of only values beginning with 'ccc-'.
  8. Type '0', and press 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|

    This here is the second half of my problem, you see, there's no space between the '0' character and the cursor (again, the snippet below shall explain why a space should be there). In fact, pressing TAB neither changed the text nor displayed a hint, and further TAB presses behave the same.

In practice, what happens in step 7 is a misunderstanding. Readline "mistakes" the dash '-' character for a word-separator (and the same goes for the question-mark '?' character, if you try auto-completing 'ddd?'; other common word separators are, for example: space, tab, '='). So, since the current line buffer ends with a word separator, then it's time for a new word, right? Hence, in step 7 (that's where we are), all values are displayed upon pressing TAB.

In step 8, once the line looks like this "Input> ccc-0|", pressing TAB has no effect because the dash, being a word-separator, separates the line into two words: 'ccc', and '0'. So, the word to be completed is '0', but alas, none of the possible values start with '0', so, no effect.

Now, sadly, there's no right or wrong here. For instance, in my application, an equals-sign '=' actually is a word separator, but a dash '-' isn't. I suppose it must be a matter of configuration, but I haven't found a way to configure which characters separate words. That's what I need help with.

I'm a man of my word, so here's the code snippet I promised:

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> ")

Boys and girls, please - help! I promise to be very thankful, and even return the favor. :)

Thanks very much in advance,
Amnon G

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄意 2024-12-13 06:48:34

只需查看 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 上;如果您较早运行某些内容,则此功能可能不可用。

Just looking at the output of dir(readline), the functions get_completer_delims() and set_completer_delims() look like they might be useful. In fact, the documentation for the readline module includes:

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

I think this describes exactly what you want. This is on Python 2.6.7; if you're running something earlier perhaps this functionality isn't available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文