##// END OF EJS Templates
Allow to customise shortcuts using a traitlet (#13928)...
Allow to customise shortcuts using a traitlet (#13928) This is a refactor of keybindings code aiming to enable users to modify, disable, and add new shortcuts. Closes #13878, relates to #13879. ## Code changes - The filters are no longer defined as Python condition expression but as strings. This ensures that all shortcuts that we define can be unambiguously overridden by users from JSON config files. - All filters were moved to a new `filters.py` module - All commands previously defined in closure of `create_ipython_shortcuts(shell)` were moved to globals (which ensures nice identifier names and makes unit-testing easier) - All bindings are now collected in `KEY_BINDINGS` global variable; in future one could consider further splitting them up and moving bindings definition to respective modules (e.g. `AUTO_MATCH_BINDINGS` to `auto_match.py`). ## User-facing changes - New configuration traitlet: `c.TerminalInteractiveShell.shortcuts` - Accept single character in autosuggestion shortcut now uses <kbd>alt</kbd> + <kbd>right</kbd> instead of <kbd>right</kbd> (which is accepting the entire suggestion as in versions 8.8 and before). After a few iterations I arrived to a specification that separates the existing key/filter from the new key/filter and has a separate "create" flag used to indicate that a new shortcut should be created (rather than modifying an existing one): > Each entry on the list should be a dictionary with ``command`` key identifying the target function executed by the shortcut and at least one of the following: > - `match_keys`: list of keys used to match an existing shortcut, > - `match_filter`: shortcut filter used to match an existing shortcut, > - `new_keys`: list of keys to set, > - `new_filter`: a new shortcut filter to set > > The filters have to be composed of pre-defined verbs and joined by one of the following conjunctions: `&` (and), `|` (or), `~` (not). The pre-defined verbs are: ..... > > To disable a shortcut set `new_keys` to an empty list. To add a shortcut add key `create` with value `True`. When modifying/disabling shortcuts, `match_keys`/`match_filter` can be omitted if the provided specification uniquely identifies a shortcut to be overridden/disabled. > > When modifying a shortcut `new_filter` or `new_keys` can be omitted which will result in reuse of the existing filter/keys. > > Only shortcuts defined in IPython (and not default prompt toolkit shortcuts) can be modified or disabled.

File last commit:

r28074:875ff239
r28115:442c33cf merge
Show More
auto_match.py
104 lines | 3.0 KiB | text/x-python | PythonLexer
"""
Utilities function for keybinding with prompt toolkit.
This will be bound to specific key press and filter modes,
like whether we are in edit mode, and whether the completer is open.
"""
import re
from prompt_toolkit.key_binding import KeyPressEvent
def parenthesis(event: KeyPressEvent):
"""Auto-close parenthesis"""
event.current_buffer.insert_text("()")
event.current_buffer.cursor_left()
def brackets(event: KeyPressEvent):
"""Auto-close brackets"""
event.current_buffer.insert_text("[]")
event.current_buffer.cursor_left()
def braces(event: KeyPressEvent):
"""Auto-close braces"""
event.current_buffer.insert_text("{}")
event.current_buffer.cursor_left()
def double_quote(event: KeyPressEvent):
"""Auto-close double quotes"""
event.current_buffer.insert_text('""')
event.current_buffer.cursor_left()
def single_quote(event: KeyPressEvent):
"""Auto-close single quotes"""
event.current_buffer.insert_text("''")
event.current_buffer.cursor_left()
def docstring_double_quotes(event: KeyPressEvent):
"""Auto-close docstring (double quotes)"""
event.current_buffer.insert_text('""""')
event.current_buffer.cursor_left(3)
def docstring_single_quotes(event: KeyPressEvent):
"""Auto-close docstring (single quotes)"""
event.current_buffer.insert_text("''''")
event.current_buffer.cursor_left(3)
def raw_string_parenthesis(event: KeyPressEvent):
"""Auto-close parenthesis in raw strings"""
matches = re.match(
r".*(r|R)[\"'](-*)",
event.current_buffer.document.current_line_before_cursor,
)
dashes = matches.group(2) if matches else ""
event.current_buffer.insert_text("()" + dashes)
event.current_buffer.cursor_left(len(dashes) + 1)
def raw_string_bracket(event: KeyPressEvent):
"""Auto-close bracker in raw strings"""
matches = re.match(
r".*(r|R)[\"'](-*)",
event.current_buffer.document.current_line_before_cursor,
)
dashes = matches.group(2) if matches else ""
event.current_buffer.insert_text("[]" + dashes)
event.current_buffer.cursor_left(len(dashes) + 1)
def raw_string_braces(event: KeyPressEvent):
"""Auto-close braces in raw strings"""
matches = re.match(
r".*(r|R)[\"'](-*)",
event.current_buffer.document.current_line_before_cursor,
)
dashes = matches.group(2) if matches else ""
event.current_buffer.insert_text("{}" + dashes)
event.current_buffer.cursor_left(len(dashes) + 1)
def skip_over(event: KeyPressEvent):
"""Skip over automatically added parenthesis/quote.
(rather than adding another parenthesis/quote)"""
event.current_buffer.cursor_right()
def delete_pair(event: KeyPressEvent):
"""Delete auto-closed parenthesis"""
event.current_buffer.delete()
event.current_buffer.delete_before_cursor()
auto_match_parens = {"(": parenthesis, "[": brackets, "{": braces}
auto_match_parens_raw_string = {
"(": raw_string_parenthesis,
"[": raw_string_bracket,
"{": raw_string_braces,
}