prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.32k stars 714 forks source link

NestedCompleter doesn't work if there is a dash in the word #1280

Open famzah opened 3 years ago

famzah commented 3 years ago

If I have the word "multi-test", for example, auto-completion treats the dash "-" as a whitespace separator. It won't continue after "multi".

To fix this I used the following patch:

--- /usr/local/lib/python3.7/dist-packages/prompt_toolkit/completion/nested.py  2020-10-23 19:54:59.873439073 +0000
+++ NestedCompleterFixed.py     2020-10-25 14:40:35.306087935 +0000
@@ -7,6 +7,8 @@
 from prompt_toolkit.completion.word_completer import WordCompleter
 from prompt_toolkit.document import Document

+import re
+
 __all__ = ["NestedCompleter"]

 # NestedDict = Mapping[str, Union['NestedDict', Set[str], None, Completer]]
@@ -103,7 +105,8 @@
         # No space in the input: behave exactly like `WordCompleter`.
         else:
             completer = WordCompleter(
-                list(self.options.keys()), ignore_case=self.ignore_case
+                list(self.options.keys()), ignore_case=self.ignore_case,
+                pattern=re.compile(r'.*') # or else "-" breaks the completion
             )
             for c in completer.get_completions(document, complete_event):
                 yield c

I don't know if this is a correct fix but it works for me.

If this is the correct solution, then maybe you can add this as an argument in __init__().

thehunmonkgroup commented 1 year ago

I'm having the same issue, but for a different reason: my commands start with a special character.

I'm pretty sure your fix is not the correct solution. From the doc of the WordCompleter class:

:param pattern: Optional compiled regex for finding the word before
    the cursor to complete. When given, use this regex pattern instead of
    default one (see document._FIND_WORD_RE)

So in effect your regex is completely defeating the _FIND_WORD_RE regex, which is probably too permissive.

What I'm doing right now is just monkey patching document at the top of my code, and adjusting document._FIND_WORD_RE:

import prompt_toolkit.document as document
document._FIND_WORD_RE = re.compile(r"([a-zA-Z0-9_" + COMMAND_LEADER + r"]+|[^a-zA-Z0-9_\s]+)")

Still not a perfect regex, but better.

It would be very helpful to be able to pass arguments to NestedCompleter that would be passed on to the WordCompleter instance -- neither one of the cases discussed in this issue seem too crazy, and it would be nice to have a little more control.