Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No completion for choices with whitespace. #32

Open
mhils opened this issue Oct 18, 2019 · 1 comment
Open

No completion for choices with whitespace. #32

mhils opened this issue Oct 18, 2019 · 1 comment

Comments

@mhils
Copy link

mhils commented Oct 18, 2019

Hi there,

Thanks for the fantastic library! 😃 Small bug report: I am encountering some issues with completing arguments that contain whitespace:

@click.command()
@click.option("--foo", type=click.Choice(["Foo Bar", "Foo Qux"]))
def cli(foo):
    print(foo)
λ cli --foo
<TAB>
λ cli --foo Foo\ 
<TAB>
(nothing changes and no options are displayed)

click-completion: 0.5.2
shell: fish

My suspicion was that the .endswith check here could be culprit:

args = split_args(commandline)[1:]
if args and not commandline.endswith(' '):
incomplete = args[-1]
args = args[:-1]
else:
incomplete = ''
I patched split_args to return an (args, incomplete) tuple, but that did not cut it (edit: see below). Given that the changes got rather messy at this point, I stopped here hoping there might be an easier fix. :)

@mhils
Copy link
Author

mhils commented Oct 18, 2019

Ok, turns out my initial patching attempt was incomplete. This works and fixes the issue:

diff --git a/click_completion/core.py b/click_completion/core.py
index 867085e..4f83e48 100644
--- a/click_completion/core.py
+++ b/click_completion/core.py
@@ -188,12 +188,8 @@ def do_fish_complete(cli, prog_name):
         True if the completion was successful, False otherwise
     """
     commandline = os.environ['COMMANDLINE']
-    args = split_args(commandline)[1:]
-    if args and not commandline.endswith(' '):
-        incomplete = args[-1]
-        args = args[:-1]
-    else:
-        incomplete = ''
+    args, incomplete = split_args(commandline)
+    args = args[1:]
 
     for item, help in get_choices(cli, prog_name, args, incomplete):
         if help:
diff --git a/click_completion/lib.py b/click_completion/lib.py
index fc195cd..ddee5da 100644
--- a/click_completion/lib.py
+++ b/click_completion/lib.py
@@ -101,23 +101,35 @@ def split_args(line):
 
     Returns
     -------
-    [str]
-        The line split in separated arguments
+    [str], str
+        The line split in separated arguments, plus the last incomplete argument (if any)
     """
     lex = shlex.shlex(line, posix=True)
     lex.whitespace_split = True
     lex.commenters = ''
     res = []
+    last_state = lex.state
     try:
         while True:
+            last_state = lex.state
             res.append(next(lex))
     except ValueError:  # No closing quotation
-        pass
+        return res, lex.token
     except StopIteration:  # End of loop
-        pass
-    if lex.token:
-        res.append(lex.token)
-    return res
+        if last_state is None:
+            return res[:-1], res[-1]
+        else:
+            return res, ''
+
+
+def test_split_args():
+    assert split_args("foo bar") == (["foo"], "bar")
+    assert split_args("foo bar ") == (["foo", "bar"], "")
+    assert split_args("foo 'bar") == (["foo"], "bar")
+    assert split_args("foo 'bar ") == (["foo"], "bar ")
+    assert split_args("foo 'bar baz'") == (["foo"], "bar baz")
+    assert split_args("foo 'bar baz' ") == (["foo", "bar baz"], "")
+    assert split_args("foo bar\\ ") == (["foo"], "bar ")

There's the obvious question if the same sort of fix should be applied to the other shells as well. Any thoughts?

mhils added a commit to mhils/click-completion that referenced this issue Oct 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant