mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
fix: append space at the end of completions (#4611)
This commit is contained in:
parent
af06aa8311
commit
cd57240237
3 changed files with 80 additions and 19 deletions
27
tests/xontribs/test_fish_completer.py
Normal file
27
tests/xontribs/test_fish_completer.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fish_completer(tmpdir, xession, load_xontrib, fake_process):
|
||||||
|
"""vox Alias function"""
|
||||||
|
load_xontrib("fish_completer")
|
||||||
|
xession.env.update(
|
||||||
|
dict(
|
||||||
|
XONSH_DATA_DIR=str(tmpdir),
|
||||||
|
XONSH_SHOW_TRACEBACK=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fake_process.register_subprocess(
|
||||||
|
command=["fish", fake_process.any()],
|
||||||
|
# completion for "git chec"
|
||||||
|
stdout=b"""\
|
||||||
|
cherry-pick Apply the change introduced by an existing commit
|
||||||
|
checkout Checkout and switch to a branch""",
|
||||||
|
)
|
||||||
|
|
||||||
|
return fake_process
|
||||||
|
|
||||||
|
|
||||||
|
def test_fish_completer(fish_completer, check_completer):
|
||||||
|
assert check_completer("git", prefix="chec") == {"checkout", "cherry-pick"}
|
|
@ -81,6 +81,27 @@ class CommandContext(NamedTuple):
|
||||||
else:
|
else:
|
||||||
return f"{self.opening_quote}{self.prefix}"
|
return f"{self.opening_quote}{self.prefix}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def command(self):
|
||||||
|
if self.args:
|
||||||
|
return self.args[0].raw_value
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def words_before_cursor(self) -> str:
|
||||||
|
"""words without current prefix"""
|
||||||
|
return " ".join([arg.raw_value for arg in self.args[: self.arg_index]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text_before_cursor(self) -> str:
|
||||||
|
"""full text before cursor including prefix"""
|
||||||
|
return self.words_before_cursor + " " + self.prefix
|
||||||
|
|
||||||
|
@property
|
||||||
|
def begidx(self) -> int:
|
||||||
|
"""cursor's position"""
|
||||||
|
return len(self.text_before_cursor)
|
||||||
|
|
||||||
|
|
||||||
class PythonContext(NamedTuple):
|
class PythonContext(NamedTuple):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,43 +1,56 @@
|
||||||
from xonsh.completers import completer
|
from xonsh.completers import completer
|
||||||
from xonsh.completers.tools import (
|
from xonsh.completers.tools import RichCompletion, contextual_command_completer
|
||||||
RichCompletion,
|
import os
|
||||||
contextual_command_completer,
|
|
||||||
get_filter_function,
|
|
||||||
)
|
|
||||||
|
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
from xonsh.built_ins import XSH
|
from xonsh.built_ins import XSH
|
||||||
from xonsh.parsers.completion_context import CommandContext
|
from xonsh.parsers.completion_context import CommandContext
|
||||||
|
|
||||||
|
|
||||||
def create_rich_completion(line: str):
|
def create_rich_completion(line: str, append_space=False):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if "\t" in line:
|
if "\t" in line:
|
||||||
cmd, desc = map(str.strip, line.split("\t", maxsplit=1))
|
cmd, desc = map(str.strip, line.split("\t", maxsplit=1))
|
||||||
else:
|
else:
|
||||||
cmd, desc = line, ""
|
cmd, desc = line, ""
|
||||||
|
|
||||||
|
# special treatment for path completions.
|
||||||
|
# not appending space even if it is a single candidate.
|
||||||
|
if cmd.endswith(os.pathsep):
|
||||||
|
append_space = False
|
||||||
|
|
||||||
return RichCompletion(
|
return RichCompletion(
|
||||||
str(cmd),
|
cmd,
|
||||||
description=str(desc),
|
description=desc,
|
||||||
append_space=True,
|
append_space=append_space,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@contextual_command_completer
|
@contextual_command_completer
|
||||||
def fish_proc_completer(ctx: CommandContext):
|
def fish_proc_completer(ctx: CommandContext):
|
||||||
"""Populate completions using fish shell and remove bash-completer"""
|
"""Populate completions using fish shell and remove bash-completer"""
|
||||||
args = [arg.value for arg in ctx.args] + [ctx.prefix]
|
if not ctx.args:
|
||||||
line = " ".join(args)
|
return
|
||||||
args = ["fish", "-c", f"complete -C '{line}'"]
|
line = ctx.text_before_cursor
|
||||||
|
|
||||||
|
script_lines = [
|
||||||
|
f"complete --no-files {ctx.command}", # switch off basic file completions for the executable
|
||||||
|
f"complete -C '{line}'",
|
||||||
|
]
|
||||||
|
args = ["fish", "-c", "; ".join(script_lines)]
|
||||||
env = XSH.env.detype()
|
env = XSH.env.detype()
|
||||||
output = sp.check_output(args, env=env).decode()
|
try:
|
||||||
filter_func = get_filter_function()
|
output = sp.check_output(args, env=env).decode()
|
||||||
|
except Exception as ex:
|
||||||
|
print(f"Failed to get fish-completions: {ex}")
|
||||||
|
return
|
||||||
|
|
||||||
if output:
|
if output:
|
||||||
for line in output.strip().splitlines(keepends=False):
|
lines = output.strip().splitlines(keepends=False)
|
||||||
comp = create_rich_completion(line)
|
# if there is a single completion candidate then maybe it is over
|
||||||
if filter_func(comp, ctx.prefix):
|
append_space = len(lines) == 1
|
||||||
yield comp
|
for line in lines:
|
||||||
|
comp = create_rich_completion(line, append_space)
|
||||||
|
yield comp
|
||||||
|
|
||||||
|
|
||||||
completer.add_one_completer("fish", fish_proc_completer, "<bash")
|
completer.add_one_completer("fish", fish_proc_completer, "<bash")
|
||||||
|
|
Loading…
Add table
Reference in a new issue