mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-07 01:40:58 +01:00
Support ptk 2.0
This commit is contained in:
parent
e9476a9734
commit
a5b5b9acf5
4 changed files with 217 additions and 30 deletions
|
@ -6,6 +6,7 @@ from prompt_toolkit.enums import DEFAULT_BUFFER
|
|||
from prompt_toolkit.filters import (Condition, IsMultiline, HasSelection,
|
||||
EmacsInsertMode, ViInsertMode)
|
||||
from prompt_toolkit.keys import Keys
|
||||
from prompt_toolkit.application.current import get_app
|
||||
|
||||
from xonsh.aliases import xonsh_exit
|
||||
from xonsh.tools import check_for_partial_string, get_line_continuation
|
||||
|
@ -84,34 +85,36 @@ def can_compile(src):
|
|||
|
||||
|
||||
@Condition
|
||||
def tab_insert_indent(cli):
|
||||
def tab_insert_indent():
|
||||
"""Check if <Tab> should insert indent instead of starting autocompletion.
|
||||
Checks if there are only whitespaces before the cursor - if so indent
|
||||
should be inserted, otherwise autocompletion.
|
||||
|
||||
"""
|
||||
before_cursor = cli.current_buffer.document.current_line_before_cursor
|
||||
before_cursor = get_app(
|
||||
).current_buffer.document.current_line_before_cursor
|
||||
|
||||
return bool(before_cursor.isspace())
|
||||
|
||||
|
||||
@Condition
|
||||
def beginning_of_line(cli):
|
||||
def beginning_of_line():
|
||||
"""Check if cursor is at beginning of a line other than the first line in a
|
||||
multiline document
|
||||
"""
|
||||
before_cursor = cli.current_buffer.document.current_line_before_cursor
|
||||
app = get_app()
|
||||
before_cursor = app.current_buffer.document.current_line_before_cursor
|
||||
|
||||
return bool(len(before_cursor) == 0 and
|
||||
not cli.current_buffer.document.on_first_line)
|
||||
not app.current_buffer.document.on_first_line)
|
||||
|
||||
|
||||
@Condition
|
||||
def end_of_line(cli):
|
||||
def end_of_line():
|
||||
"""Check if cursor is at the end of a line other than the last line in a
|
||||
multiline document
|
||||
"""
|
||||
d = cli.current_buffer.document
|
||||
d = get_app().current_buffer.document
|
||||
at_end = d.is_cursor_at_the_end_of_line
|
||||
last_line = d.is_cursor_at_the_end
|
||||
|
||||
|
@ -119,56 +122,57 @@ def end_of_line(cli):
|
|||
|
||||
|
||||
@Condition
|
||||
def should_confirm_completion(cli):
|
||||
def should_confirm_completion():
|
||||
"""Check if completion needs confirmation"""
|
||||
return (builtins.__xonsh_env__.get('COMPLETIONS_CONFIRM') and
|
||||
cli.current_buffer.complete_state)
|
||||
get_app().current_buffer.complete_state)
|
||||
|
||||
|
||||
# Copied from prompt-toolkit's key_binding/bindings/basic.py
|
||||
@Condition
|
||||
def ctrl_d_condition(cli):
|
||||
def ctrl_d_condition():
|
||||
"""Ctrl-D binding is only active when the default buffer is selected and
|
||||
empty.
|
||||
"""
|
||||
if builtins.__xonsh_env__.get("IGNOREEOF"):
|
||||
raise EOFError
|
||||
else:
|
||||
return (cli.current_buffer_name == DEFAULT_BUFFER and
|
||||
not cli.current_buffer.text)
|
||||
app = get_app()
|
||||
return (app.current_buffer_name == DEFAULT_BUFFER and
|
||||
not app.current_buffer.text)
|
||||
|
||||
|
||||
@Condition
|
||||
def autopair_condition(cli):
|
||||
def autopair_condition():
|
||||
"""Check if XONSH_AUTOPAIR is set"""
|
||||
return builtins.__xonsh_env__.get("XONSH_AUTOPAIR", False)
|
||||
|
||||
|
||||
@Condition
|
||||
def whitespace_or_bracket_before(cli):
|
||||
def whitespace_or_bracket_before():
|
||||
"""Check if there is whitespace or an opening
|
||||
bracket to the left of the cursor"""
|
||||
d = cli.current_buffer.document
|
||||
d = get_app().current_buffer.document
|
||||
return bool(d.cursor_position == 0
|
||||
or d.char_before_cursor.isspace()
|
||||
or d.char_before_cursor in '([{')
|
||||
|
||||
|
||||
@Condition
|
||||
def whitespace_or_bracket_after(cli):
|
||||
def whitespace_or_bracket_after():
|
||||
"""Check if there is whitespace or a closing
|
||||
bracket to the right of the cursor"""
|
||||
d = cli.current_buffer.document
|
||||
d = get_app().current_buffer.document
|
||||
return bool(d.is_cursor_at_the_end_of_line
|
||||
or d.current_char.isspace()
|
||||
or d.current_char in ')]}')
|
||||
|
||||
|
||||
def load_xonsh_bindings(key_bindings_manager):
|
||||
def load_xonsh_bindings(key_bindings):
|
||||
"""
|
||||
Load custom key bindings.
|
||||
"""
|
||||
handle = key_bindings_manager.registry.add_binding
|
||||
handle = key_bindings.add
|
||||
has_selection = HasSelection()
|
||||
insert_mode = ViInsertMode() | EmacsInsertMode()
|
||||
|
||||
|
|
|
@ -3,24 +3,37 @@
|
|||
import sys
|
||||
import builtins
|
||||
|
||||
from prompt_toolkit.key_binding.manager import KeyBindingManager
|
||||
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||
from prompt_toolkit.layout.lexers import PygmentsLexer
|
||||
from prompt_toolkit.shortcuts import print_tokens
|
||||
from prompt_toolkit.styles import PygmentsStyle, style_from_dict
|
||||
|
||||
from xonsh.platform import ptk_version_info
|
||||
from xonsh.base_shell import BaseShell
|
||||
from xonsh.tools import print_exception, carriage_return
|
||||
from xonsh.ptk.completer import PromptToolkitCompleter
|
||||
from xonsh.ptk.history import PromptToolkitHistory
|
||||
from xonsh.ptk.key_bindings import load_xonsh_bindings
|
||||
from xonsh.ptk.shortcuts import Prompter
|
||||
from xonsh.ptk.shortcuts import get_prompter
|
||||
from xonsh.events import events
|
||||
from xonsh.shell import transform_command
|
||||
from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS
|
||||
from xonsh.style_tools import partial_color_tokenize, _TokenType, DEFAULT_STYLE_DICT
|
||||
from xonsh.lazyimps import pygments, pyghooks, winutils
|
||||
|
||||
|
||||
if ptk_version_info()[:2] < (2, 0):
|
||||
from prompt_toolkit.key_binding.manager import KeyBindingManager
|
||||
from prompt_toolkit.shortcuts import print_tokens as ptk_print
|
||||
from prompt_toolkit.styles import style_from_dict
|
||||
from prompt_toolkit.styles import PygmentsStyle as style_from_pygments
|
||||
else: # ptk 2.0
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
from prompt_toolkit.shortcuts import print_formatted_text as ptk_print
|
||||
from prompt_toolkit.shortcuts import CompleteStyle
|
||||
from prompt_toolkit.formatted_text import PygmentsTokens
|
||||
from prompt_toolkit.styles.pygments import (
|
||||
style_from_pygments, Style, pygments_token_to_classname)
|
||||
|
||||
|
||||
Token = _TokenType()
|
||||
|
||||
events.transmogrify('on_ptk_create', 'LoadEvent')
|
||||
|
@ -39,7 +52,7 @@ class PromptToolkitShell(BaseShell):
|
|||
if ON_WINDOWS:
|
||||
winutils.enable_virtual_terminal_processing()
|
||||
self._first_prompt = True
|
||||
self.prompter = Prompter()
|
||||
self.prompter = get_prompter()
|
||||
self.history = PromptToolkitHistory()
|
||||
self.pt_completer = PromptToolkitCompleter(self.completer, self.ctx, self)
|
||||
key_bindings_manager_args = {
|
||||
|
@ -270,10 +283,10 @@ class PromptToolkitShell(BaseShell):
|
|||
if HAS_PYGMENTS:
|
||||
env = builtins.__xonsh_env__
|
||||
self.styler.style_name = env.get('XONSH_COLOR_STYLE')
|
||||
proxy_style = PygmentsStyle(pyghooks.xonsh_style_proxy(self.styler))
|
||||
proxy_style = style_from_pygments(pyghooks.xonsh_style_proxy(self.styler))
|
||||
else:
|
||||
proxy_style = style_from_dict(DEFAULT_STYLE_DICT)
|
||||
print_tokens(tokens, style=proxy_style)
|
||||
ptk_print(tokens, style=proxy_style)
|
||||
|
||||
def color_style_names(self):
|
||||
"""Returns an iterable of all available style names."""
|
||||
|
@ -312,3 +325,118 @@ class PromptToolkitShell(BaseShell):
|
|||
# if not ON_POSIX:
|
||||
# return
|
||||
# sys.stdout.write('\033[9999999C\n')
|
||||
|
||||
|
||||
class PromptToolkitShell2(PromptToolkitShell):
|
||||
"""The xonsh shell for ptk 2.0.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
super(PromptToolkitShell, self).__init__(**kwargs)
|
||||
if ON_WINDOWS:
|
||||
winutils.enable_virtual_terminal_processing()
|
||||
self._first_prompt = True
|
||||
self.prompter = get_prompter()
|
||||
self.history = PromptToolkitHistory()
|
||||
self.pt_completer = PromptToolkitCompleter(
|
||||
self.completer, self.ctx, self)
|
||||
self.key_bindings = KeyBindings()
|
||||
load_xonsh_bindings(self.key_bindings)
|
||||
# This assumes that PromptToolkitShell is a singleton
|
||||
events.on_ptk_create.fire(
|
||||
prompter=self.prompter,
|
||||
history=self.history,
|
||||
completer=self.pt_completer,
|
||||
bindings=self.key_bindings,
|
||||
)
|
||||
|
||||
def singleline(self, store_in_history=True, auto_suggest=None,
|
||||
enable_history_search=True, multiline=True, **kwargs):
|
||||
"""Reads a single line of input from the shell. The store_in_history
|
||||
kwarg flags whether the input should be stored in PTK's in-memory
|
||||
history.
|
||||
"""
|
||||
events.on_pre_prompt.fire()
|
||||
env = builtins.__xonsh_env__
|
||||
mouse_support = env.get('MOUSE_SUPPORT')
|
||||
if store_in_history:
|
||||
history = self.history
|
||||
else:
|
||||
history = None
|
||||
enable_history_search = False
|
||||
auto_suggest = auto_suggest if env.get('AUTO_SUGGEST') else None
|
||||
completions_display = env.get('COMPLETIONS_DISPLAY')
|
||||
if completions_display == 'multi':
|
||||
complete_style = CompleteStyle.MULTI_COLUMN
|
||||
complete_while_typing = env.get('UPDATE_COMPLETIONS_ON_KEYPRESS')
|
||||
if complete_while_typing:
|
||||
# PTK requires history search to be none when completing while typing
|
||||
enable_history_search = False
|
||||
if HAS_PYGMENTS:
|
||||
self.styler.style_name = env.get('XONSH_COLOR_STYLE')
|
||||
completer = None if completions_display == 'none' else self.pt_completer
|
||||
|
||||
if not env.get('UPDATE_PROMPT_ON_KEYPRESS'):
|
||||
get_prompt_tokens = self.prompt_tokens(None)
|
||||
get_rprompt_tokens = self.rprompt_tokens(None)
|
||||
get_bottom_toolbar_tokens = self.bottom_toolbar_tokens(None)
|
||||
else:
|
||||
get_prompt_tokens = self.prompt_tokens
|
||||
get_rprompt_tokens = self.rprompt_tokens
|
||||
get_bottom_toolbar_tokens = self.bottom_toolbar_tokens
|
||||
|
||||
with self.prompter:
|
||||
prompt_args = {
|
||||
'mouse_support': mouse_support,
|
||||
'auto_suggest': auto_suggest,
|
||||
'message': get_prompt_tokens,
|
||||
'rprompt': get_rprompt_tokens,
|
||||
'bottom_toolbar': get_bottom_toolbar_tokens,
|
||||
'completer': completer,
|
||||
'multiline': multiline,
|
||||
'prompt_continuation': self.continuation_tokens,
|
||||
'history': history,
|
||||
'enable_history_search': enable_history_search,
|
||||
'reserve_space_for_menu': 0,
|
||||
'extra_key_bindings': self.key_bindings,
|
||||
'complete_style': complete_style,
|
||||
'complete_while_typing': complete_while_typing,
|
||||
}
|
||||
if builtins.__xonsh_env__.get('COLOR_INPUT'):
|
||||
if HAS_PYGMENTS:
|
||||
prompt_args['lexer'] = PygmentsLexer(pyghooks.XonshLexer)
|
||||
style = style_from_pygments(
|
||||
pyghooks.xonsh_style_proxy(self.styler))
|
||||
else:
|
||||
style_dict = {
|
||||
pygments_token_to_classname(key.__name__): value
|
||||
for key, value in DEFAULT_STYLE_DICT
|
||||
}
|
||||
style = Style.from_dict(style_dict)
|
||||
|
||||
prompt_args['style'] = style
|
||||
|
||||
line = self.prompter.prompt(**prompt_args)
|
||||
events.on_post_prompt.fire()
|
||||
return line
|
||||
|
||||
def prompt_tokens(self, cli):
|
||||
return PygmentsTokens(super().prompt_tokens(cli))
|
||||
|
||||
def rprompt_tokens(self, cli):
|
||||
return PygmentsTokens(super().rprompt_tokens(cli))
|
||||
|
||||
def bottom_toolbar_tokens(self, cli):
|
||||
return PygmentsTokens(super().bottom_toolbar_tokens(cli))
|
||||
|
||||
def continuation_tokens(self, width, cli=None):
|
||||
return PygmentsTokens(
|
||||
super().continuation_tokens(width=width, cli=cli))
|
||||
|
||||
|
||||
def get_ptk_shell(**kwargs):
|
||||
"""Return a new ptk shell wrapper based on the installed version.
|
||||
"""
|
||||
if ptk_version_info()[:2] < (2, 0):
|
||||
return PromptToolkitShell(**kwargs)
|
||||
else:
|
||||
return PromptToolkitShell2(**kwargs)
|
||||
|
|
|
@ -2,15 +2,20 @@
|
|||
import builtins
|
||||
import textwrap
|
||||
|
||||
from prompt_toolkit.interface import CommandLineInterface
|
||||
from prompt_toolkit.enums import EditingMode
|
||||
from prompt_toolkit.utils import DummyContext
|
||||
from prompt_toolkit.shortcuts import (create_prompt_application,
|
||||
create_eventloop, create_asyncio_eventloop, create_output)
|
||||
|
||||
from xonsh.platform import ptk_version_info
|
||||
import xonsh.tools as xt
|
||||
|
||||
if ptk_version_info()[:2] < (2, 0):
|
||||
from prompt_toolkit.interface import CommandLineInterface
|
||||
from prompt_toolkit.shortcuts import (
|
||||
create_prompt_application, create_eventloop, create_asyncio_eventloop,
|
||||
create_output)
|
||||
else:
|
||||
from prompt_toolkit.shortcuts import Prompt
|
||||
|
||||
|
||||
class Prompter(object):
|
||||
|
||||
|
@ -120,3 +125,53 @@ class Prompter(object):
|
|||
def reset(self):
|
||||
"""Resets the prompt and cli to a pristine state on this object."""
|
||||
self.cli = None
|
||||
|
||||
|
||||
class Prompter2(object):
|
||||
"""Prompter for ptk 2.0
|
||||
"""
|
||||
def __init__(self, cli=None, *args, **kwargs):
|
||||
"""Implements a prompt that statefully holds a command-line
|
||||
interface. When used as a context manager, it will return itself
|
||||
on entry and reset itself on exit.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cli : CommandLineInterface or None, optional
|
||||
If this is not a CommandLineInterface object, such an object
|
||||
will be created when the prompt() method is called.
|
||||
"""
|
||||
# TODO: maybe call this ``.prompt`` now since
|
||||
# ``CommandLineInterface`` is gone?
|
||||
self.cli = cli or Prompt(**kwargs)
|
||||
self.major_minor = ptk_version_info()[:2]
|
||||
|
||||
def __enter__(self):
|
||||
self.reset()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def prompt(self, message='', **kwargs):
|
||||
"""Get input from the user and return it.
|
||||
"""
|
||||
if builtins.__xonsh_env__.get('VI_MODE'):
|
||||
editing_mode = EditingMode.VI
|
||||
else:
|
||||
editing_mode = EditingMode.EMACS
|
||||
|
||||
kwargs['editing_mode'] = editing_mode
|
||||
self.cli.prompt(message=message, **kwargs)
|
||||
|
||||
def reset(self):
|
||||
"""Resets the prompt and cli to a pristine state on this object."""
|
||||
# XXX Is this necessary any more?
|
||||
# self.prompt = None
|
||||
|
||||
|
||||
def get_prompter():
|
||||
if ptk_version_info()[:2] < (2, 0):
|
||||
return Prompter()
|
||||
else:
|
||||
return Prompter2()
|
||||
|
|
|
@ -142,7 +142,7 @@ class Shell(object):
|
|||
if shell_type == 'none':
|
||||
from xonsh.base_shell import BaseShell as shell_class
|
||||
elif shell_type == 'prompt_toolkit':
|
||||
from xonsh.ptk.shell import PromptToolkitShell as shell_class
|
||||
from xonsh.ptk.shell import get_ptk_shell as shell_class
|
||||
elif shell_type == 'readline':
|
||||
from xonsh.readline_shell import ReadlineShell as shell_class
|
||||
else:
|
||||
|
|
Loading…
Add table
Reference in a new issue