mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00
Merge pull request #2218 from xonsh/ghost-in-the-sh
Complete based on autosuggestion
This commit is contained in:
commit
11593f80ac
3 changed files with 74 additions and 38 deletions
14
news/ghost-in-the-sh.rst
Normal file
14
news/ghost-in-the-sh.rst
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
**Added:** None
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
|
||||||
|
* The prompt toolkit shell's first completion will now be the
|
||||||
|
current token from the auto-suggetion, if available.
|
||||||
|
|
||||||
|
**Deprecated:** None
|
||||||
|
|
||||||
|
**Removed:** None
|
||||||
|
|
||||||
|
**Fixed:** None
|
||||||
|
|
||||||
|
**Security:** None
|
|
@ -5,6 +5,7 @@ import builtins
|
||||||
|
|
||||||
from prompt_toolkit.layout.dimension import LayoutDimension
|
from prompt_toolkit.layout.dimension import LayoutDimension
|
||||||
from prompt_toolkit.completion import Completer, Completion
|
from prompt_toolkit.completion import Completer, Completion
|
||||||
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||||
|
|
||||||
|
|
||||||
class PromptToolkitCompleter(Completer):
|
class PromptToolkitCompleter(Completer):
|
||||||
|
@ -13,54 +14,75 @@ class PromptToolkitCompleter(Completer):
|
||||||
It just redirects requests to normal Xonsh completer.
|
It just redirects requests to normal Xonsh completer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, completer, ctx):
|
def __init__(self, completer, ctx, shell):
|
||||||
"""Takes instance of xonsh.completer.Completer and dict with context."""
|
"""Takes instance of xonsh.completer.Completer, the xonsh execution
|
||||||
|
context, and the shell instance itself.
|
||||||
|
"""
|
||||||
self.completer = completer
|
self.completer = completer
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
|
self.shell = shell
|
||||||
|
self.hist_suggester = AutoSuggestFromHistory()
|
||||||
|
|
||||||
def get_completions(self, document, complete_event):
|
def get_completions(self, document, complete_event):
|
||||||
"""Returns a generator for list of completions."""
|
"""Returns a generator for list of completions."""
|
||||||
|
env = builtins.__xonsh_env__
|
||||||
should_complete = (
|
should_complete = (
|
||||||
complete_event.completion_requested or
|
complete_event.completion_requested or
|
||||||
builtins.__xonsh_env__.get('UPDATE_COMPLETIONS_ON_KEYPRESS')
|
env.get('UPDATE_COMPLETIONS_ON_KEYPRESS')
|
||||||
)
|
)
|
||||||
# Only generate completions when the user hits tab.
|
# Only generate completions when the user hits tab.
|
||||||
if should_complete:
|
if not should_complete or self.completer is None:
|
||||||
if self.completer is None:
|
return
|
||||||
yield from []
|
# generate actual completions
|
||||||
|
line = document.current_line.lstrip()
|
||||||
|
line_ex = builtins.aliases.expand_alias(line)
|
||||||
|
|
||||||
|
endidx = document.cursor_position_col
|
||||||
|
begidx = (line[:endidx].rfind(' ') + 1
|
||||||
|
if line[:endidx].rfind(' ') >= 0 else 0)
|
||||||
|
prefix = line[begidx:endidx]
|
||||||
|
expand_offset = len(line_ex) - len(line)
|
||||||
|
# get normal completions
|
||||||
|
completions, l = self.completer.complete(prefix, line_ex,
|
||||||
|
begidx + expand_offset,
|
||||||
|
endidx + expand_offset,
|
||||||
|
self.ctx)
|
||||||
|
# completions from auto suggest
|
||||||
|
if env.get('AUTO_SUGGEST'):
|
||||||
|
sug_comp = self.suggestion_completion(document, line)
|
||||||
|
if sug_comp is None:
|
||||||
|
pass
|
||||||
|
elif len(completions) == 0:
|
||||||
|
completions = (sug_comp,)
|
||||||
else:
|
else:
|
||||||
line = document.current_line.lstrip()
|
completions = (sug_comp,) + completions
|
||||||
line_ex = builtins.aliases.expand_alias(line)
|
# reserve space, if needed.
|
||||||
|
if len(completions) <= 1:
|
||||||
|
pass
|
||||||
|
elif len(os.path.commonprefix(completions)) <= len(prefix):
|
||||||
|
self.reserve_space()
|
||||||
|
# Find common prefix (strip quoting)
|
||||||
|
c_prefix = os.path.commonprefix([a.strip('\'"') for a in completions])
|
||||||
|
# Find last split symbol, do not trim the last part
|
||||||
|
while c_prefix:
|
||||||
|
if c_prefix[-1] in r'/\.:@,':
|
||||||
|
break
|
||||||
|
c_prefix = c_prefix[:-1]
|
||||||
|
# yield completions
|
||||||
|
for comp in completions:
|
||||||
|
# do not display quote
|
||||||
|
disp = comp.strip('\'"')[len(c_prefix):]
|
||||||
|
yield Completion(comp, -l, display=disp)
|
||||||
|
|
||||||
endidx = document.cursor_position_col
|
def suggestion_completion(self, document, line):
|
||||||
begidx = (line[:endidx].rfind(' ') + 1
|
"""Provides a completion based on the current auto-suggestion."""
|
||||||
if line[:endidx].rfind(' ') >= 0 else 0)
|
cli = self.shell.prompter.cli
|
||||||
prefix = line[begidx:endidx]
|
sug = self.hist_suggester.get_suggestion(cli, cli.current_buffer, document)
|
||||||
expand_offset = len(line_ex) - len(line)
|
if sug is None:
|
||||||
|
return None
|
||||||
completions, l = self.completer.complete(prefix,
|
comp, _, _ = sug.text.partition(' ')
|
||||||
line_ex,
|
_, _, prev = line.rpartition(' ')
|
||||||
begidx + expand_offset,
|
return prev + comp
|
||||||
endidx + expand_offset,
|
|
||||||
self.ctx)
|
|
||||||
if len(completions) <= 1:
|
|
||||||
pass
|
|
||||||
elif len(os.path.commonprefix(completions)) <= len(prefix):
|
|
||||||
self.reserve_space()
|
|
||||||
|
|
||||||
# Find common prefix (strip quoting)
|
|
||||||
c_prefix = os.path.commonprefix([a.strip('\'"')
|
|
||||||
for a in completions])
|
|
||||||
# Find last split symbol, do not trim the last part
|
|
||||||
while c_prefix:
|
|
||||||
if c_prefix[-1] in r'/\.:@,':
|
|
||||||
break
|
|
||||||
c_prefix = c_prefix[:-1]
|
|
||||||
|
|
||||||
for comp in completions:
|
|
||||||
# do not display quote
|
|
||||||
disp = comp.strip('\'"')[len(c_prefix):]
|
|
||||||
yield Completion(comp, -l, display=disp)
|
|
||||||
|
|
||||||
def reserve_space(self):
|
def reserve_space(self):
|
||||||
cli = builtins.__xonsh_shell__.shell.prompter.cli
|
cli = builtins.__xonsh_shell__.shell.prompter.cli
|
||||||
|
|
|
@ -38,7 +38,7 @@ class PromptToolkitShell(BaseShell):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.prompter = Prompter()
|
self.prompter = Prompter()
|
||||||
self.history = PromptToolkitHistory()
|
self.history = PromptToolkitHistory()
|
||||||
self.pt_completer = PromptToolkitCompleter(self.completer, self.ctx)
|
self.pt_completer = PromptToolkitCompleter(self.completer, self.ctx, self)
|
||||||
key_bindings_manager_args = {
|
key_bindings_manager_args = {
|
||||||
'enable_auto_suggest_bindings': True,
|
'enable_auto_suggest_bindings': True,
|
||||||
'enable_search': True,
|
'enable_search': True,
|
||||||
|
|
Loading…
Add table
Reference in a new issue