Source code for xonsh.ptk2.completer
# -*- coding: utf-8 -*-
"""Completer implementation to use with prompt_toolkit."""
import os
import builtins
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.application.current import get_app
[docs]class PromptToolkitCompleter(Completer):
"""Simple prompt_toolkit Completer object.
It just redirects requests to normal Xonsh completer.
"""
def __init__(self, completer, ctx, shell):
"""Takes instance of xonsh.completer.Completer, the xonsh execution
context, and the shell instance itself.
"""
self.completer = completer
self.ctx = ctx
self.shell = shell
self.hist_suggester = AutoSuggestFromHistory()
[docs] def get_completions(self, document, complete_event):
"""Returns a generator for list of completions."""
env = builtins.__xonsh__.env
should_complete = complete_event.completion_requested or env.get(
"UPDATE_COMPLETIONS_ON_KEYPRESS"
)
# Only generate completions when the user hits tab.
if not should_complete or self.completer is None:
return
# 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
sug_comp = None
if env.get("AUTO_SUGGEST") and env.get("AUTO_SUGGEST_IN_COMPLETIONS"):
sug_comp = self.suggestion_completion(document, line)
if sug_comp is None:
pass
elif len(completions) == 0:
completions = (sug_comp,)
else:
completions = set(completions)
completions.discard(sug_comp)
completions = (sug_comp,) + tuple(sorted(completions))
# 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
if sug_comp is None:
pre = min(document.cursor_position_col - begidx, len(c_prefix))
else:
pre = len(c_prefix)
for comp in completions:
# do not display quote
disp = comp[pre:].strip("'\"")
yield Completion(comp, -l, display=disp)
[docs] def suggestion_completion(self, document, line):
"""Provides a completion based on the current auto-suggestion."""
app = self.shell.prompter.app
sug = self.hist_suggester.get_suggestion(app.current_buffer, document)
if sug is None:
return None
comp, _, _ = sug.text.partition(" ")
_, _, prev = line.rpartition(" ")
return prev + comp
[docs] def reserve_space(self):
"""Adjust the height for showing autocompletion menu."""
app = get_app()
render = app.renderer
window = app.layout.container.children[0].content.children[1].content
if window and window.render_info:
h = window.render_info.content_height
r = builtins.__xonsh__.env.get("COMPLETIONS_MENU_ROWS")
size = h + r
last_h = render._last_screen.height if render._last_screen else 0
last_h = max(render._min_available_height, last_h)
if last_h < size:
if render._last_screen:
render._last_screen.height = size