mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Use substring for env completion and better way to sort list (#5388)
### Motivation It's very annoying to search env variable exactly by lprefix. The better is to search by substring and sort results by the position of substring and then alphabetically. Closes #5386 ### Before ```xsh $TRA<Tab> # nothing ``` ### After ```xsh $TRA<Tab> # 'XONSH_TRACE_COMPLETIONS', # 'XONSH_TRACE_SUBPROC', # 'XONSH_TRACE_SUBPROC_FUNC', # 'XONSH_TRACEBACK_LOGFILE', # 'XONSH_SHOW_TRACEBACK', # 'VC_GIT_INCLUDE_UNTRACKED' ``` ## For community ⬇️ **Please click the 👍 reaction instead of leaving a `+1` or 👍 comment** --------- Co-authored-by: a <1@1.1> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
21da30e753
commit
a3e8b1a025
5 changed files with 63 additions and 20 deletions
23
news/env_completion.rst
Normal file
23
news/env_completion.rst
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
**Added:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
|
||||||
|
* Env variables completion: now use substring for search and then sort results by the position of substring and then alphabetically. PR 5388.
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Removed:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Security:**
|
||||||
|
|
||||||
|
* <news item>
|
|
@ -12,30 +12,30 @@ def parser():
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"cmd",
|
"cmd",
|
||||||
(
|
(
|
||||||
"ls $WO",
|
"ls $WOW",
|
||||||
"ls /home/$WO",
|
"ls /home/$WOW",
|
||||||
"ls '/home/$WO'",
|
"ls '/home/$WOW'",
|
||||||
"ls @('hi ' + $WO",
|
"ls @('hi ' + $WOW",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_simple(cmd, xession, monkeypatch, parser):
|
def test_simple(cmd, xession, monkeypatch, parser):
|
||||||
xession.env.update({"WOW": 1})
|
xession.env.update({"WOWZER": 1})
|
||||||
|
|
||||||
context = parser.parse(cmd, len(cmd))
|
context = parser.parse(cmd, len(cmd))
|
||||||
comps, lprefix = complete_environment_vars(context)
|
comps, lprefix = complete_environment_vars(context)
|
||||||
# account for the ending quote
|
# account for the ending quote
|
||||||
if cmd[-1] in "'":
|
if cmd[-1] in "'":
|
||||||
assert lprefix == 4
|
assert lprefix == 5
|
||||||
else:
|
else:
|
||||||
assert lprefix == 3
|
assert lprefix == 4
|
||||||
assert set(comps) == {"$WOW"}
|
assert set(comps) == {"$WOWZER"}
|
||||||
|
|
||||||
|
|
||||||
def test_rich_completions(xession, monkeypatch, parser):
|
def test_rich_completions(xession, monkeypatch, parser):
|
||||||
xession.env.update({"WOW": 1})
|
xession.env.update({"WOWZER": 1})
|
||||||
xession.env.register("WOW", type=int, doc="Nice Docs!")
|
xession.env.register("WOWZER", type=int, doc="Nice Docs!")
|
||||||
|
|
||||||
context = parser.parse("$WO", 3)
|
context = parser.parse("$WOW", 4)
|
||||||
completion = next(complete_environment_vars(context)[0])
|
completion = next(complete_environment_vars(context)[0])
|
||||||
assert completion.display == "$WOW [int]"
|
assert completion.display == "$WOWZER [int]"
|
||||||
assert completion.description == "Nice Docs!"
|
assert completion.description == "Nice Docs!"
|
||||||
|
|
|
@ -155,3 +155,16 @@ def test_non_exclusive(completer, completers_mock, middle_result, exp):
|
||||||
completers_mock["c"] = non_exclusive_completer(lambda *a: {"c1", "c2"})
|
completers_mock["c"] = non_exclusive_completer(lambda *a: {"c1", "c2"})
|
||||||
|
|
||||||
assert completer.complete("", "", 0, 0, {})[0] == exp
|
assert completer.complete("", "", 0, 0, {})[0] == exp
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_completer_sort(completer, completers_mock):
|
||||||
|
@contextual_command_completer
|
||||||
|
def comp(context: CommandContext):
|
||||||
|
return {"$SUPER_WOW", "$WOW1", "$WOW0", "$MID_WOW"}
|
||||||
|
|
||||||
|
completers_mock["a"] = comp
|
||||||
|
|
||||||
|
comps = completer.complete(
|
||||||
|
"$WOW", "$WOW", 4, 0, {}, multiline_text="'$WOW'", cursor_index=4
|
||||||
|
)
|
||||||
|
assert set(comps[0]) == {"$WOW0", "$WOW1", "$MID_WOW", "$SUPER_WOW"}
|
||||||
|
|
|
@ -284,9 +284,18 @@ class Completer:
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
def sortkey(s):
|
prefix = None
|
||||||
# todo: should sort with prefix > substring > fuzzy
|
if completion_context:
|
||||||
return s.lstrip(''''"''').lower()
|
prefix = completion_context.command.prefix
|
||||||
|
if prefix.startswith("$"):
|
||||||
|
prefix = prefix[1:]
|
||||||
|
|
||||||
|
def sortkey(s):
|
||||||
|
"""Sort values by prefix position and then alphabetically."""
|
||||||
|
return (s.lower().find(prefix.lower()), s.lower())
|
||||||
|
else:
|
||||||
|
# Fallback sort.
|
||||||
|
sortkey = lambda s: s.lstrip(''''"''').lower()
|
||||||
|
|
||||||
# the last completer's lprefix is returned. other lprefix values are inside the RichCompletions.
|
# the last completer's lprefix is returned. other lprefix values are inside the RichCompletions.
|
||||||
return tuple(sorted(completions, key=sortkey)), lprefix
|
return tuple(sorted(completions, key=sortkey)), lprefix
|
||||||
|
|
|
@ -2,7 +2,6 @@ from xonsh.built_ins import XSH
|
||||||
from xonsh.completers.tools import (
|
from xonsh.completers.tools import (
|
||||||
RichCompletion,
|
RichCompletion,
|
||||||
contextual_completer,
|
contextual_completer,
|
||||||
get_filter_function,
|
|
||||||
non_exclusive_completer,
|
non_exclusive_completer,
|
||||||
)
|
)
|
||||||
from xonsh.parsers.completion_context import CompletionContext
|
from xonsh.parsers.completion_context import CompletionContext
|
||||||
|
@ -27,15 +26,14 @@ def complete_environment_vars(context: CompletionContext):
|
||||||
lprefix = len(key) + 1
|
lprefix = len(key) + 1
|
||||||
if context.command is not None and context.command.is_after_closing_quote:
|
if context.command is not None and context.command.is_after_closing_quote:
|
||||||
lprefix += 1
|
lprefix += 1
|
||||||
filter_func = get_filter_function()
|
|
||||||
env = XSH.env
|
env = XSH.env
|
||||||
|
|
||||||
|
vars = [k for k, v in env.items() if key.lower() in k.lower()]
|
||||||
return (
|
return (
|
||||||
RichCompletion(
|
RichCompletion(
|
||||||
"$" + k,
|
"$" + k,
|
||||||
display=f"${k} [{type(v).__name__}]",
|
display=f"${k} [{type(env[k]).__name__}]",
|
||||||
description=env.get_docs(k).doc,
|
description=env.get_docs(k).doc,
|
||||||
)
|
)
|
||||||
for k, v in env.items()
|
for k in vars
|
||||||
if filter_func(k, key)
|
|
||||||
), lprefix
|
), lprefix
|
||||||
|
|
Loading…
Add table
Reference in a new issue