From f6541ad5cf96c9d52d1769be58902f460102c181 Mon Sep 17 00:00:00 2001 From: Martin Skarzynski Date: Sat, 10 Oct 2020 15:55:55 -0400 Subject: [PATCH 1/3] provide option to have tab apply completion --- radian/key_bindings.py | 87 +++++++++++++++++++++++++++++++++++++++--- radian/settings.py | 1 + 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/radian/key_bindings.py b/radian/key_bindings.py index d05d923..8939ea3 100644 --- a/radian/key_bindings.py +++ b/radian/key_bindings.py @@ -2,10 +2,12 @@ import re import os +from prompt_toolkit.completion import CompleteEvent from prompt_toolkit.application.current import get_app from prompt_toolkit.application.run_in_terminal import run_in_terminal from prompt_toolkit.eventloop import From, ensure_future from prompt_toolkit.keys import Keys +from prompt_toolkit.key_binding.key_processor import KeyPress from prompt_toolkit.key_binding.key_bindings import KeyBindings from prompt_toolkit.key_binding.bindings import named_commands as nc from prompt_toolkit.filters import Condition, has_focus, \ @@ -20,7 +22,7 @@ from radian.document import cursor_in_string from radian import get_app as get_radian_app from rchitect.interface import roption - +from rchitect import rcopy, rcall, reval from six import text_type @@ -403,11 +405,86 @@ def create_key_bindings(editor=""): kb = KeyBindings() handle = kb.add - # emit completion - @handle('c-j', filter=insert_mode & default_focused & completion_is_selected) - @handle('enter', filter=insert_mode & default_focused & completion_is_selected) + + def is_callable(text=""): + try: + return rcopy(rcall("class", reval(text))) == "function" + except: + return False + + @Condition + def tac(): + return settings.tab_apply_completion + + insert_mode = vi_insert_mode | emacs_insert_mode + focused_insert = insert_mode & has_focus(DEFAULT_BUFFER) + shown_not_selected = has_completions & ~completion_is_selected + alt_enter = [KeyPress(Keys.Escape), KeyPress(Keys.Enter)] + + # apply selected completion + @handle('c-j', filter=focused_insert & completion_is_selected & tac) + @handle("enter", filter=focused_insert & completion_is_selected & tac) + def _(event): + b = event.current_buffer + text = b.text + completion = b.complete_state.current_completion + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() + if text == b.text: + event.cli.key_processor.feed_multiple(alt_enter) + + # apply first completion option when completion menu is showing + @handle('c-j', filter=focused_insert & shown_not_selected & tac) + @handle("enter", filter=focused_insert & shown_not_selected & tac) def _(event): - event.current_buffer.complete_state = None + b = event.current_buffer + text = b.text + b.complete_next() + completion = b.complete_state.current_completion + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() + if text == b.text: + event.cli.key_processor.feed_multiple(alt_enter) + + # apply completion if there is only one option, otherwise start completion + @handle("tab", filter=focused_insert & ~has_completions & tac) + @handle("c-space", filter=focused_insert & ~has_completions & tac) + def _(event): + b = event.current_buffer + complete_event = CompleteEvent(completion_requested=True) + completions = list(b.completer.get_completions(b.document, complete_event)) + if len(completions) == 1: + completion = completions[0] + b.apply_completion(completion) + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() + else: + b.start_completion(insert_common_part=True) + + # apply first completion option if completion menu is showing + @handle("tab", filter=focused_insert & shown_not_selected & tac) + @handle("c-space", filter=focused_insert & shown_not_selected & tac) + def _(event): + b = event.current_buffer + b.complete_next() + completion = b.complete_state.current_completion + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() + + # apply selected completion option + @handle("tab", filter=focused_insert & completion_is_selected & tac) + @handle("c-space", filter=focused_insert & completion_is_selected & tac) + def _(event): + b = event.current_buffer + completion = b.complete_state.current_completion + b.apply_completion(completion) + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() # cancel completion @handle('c-c', filter=default_focused & has_completions) diff --git a/radian/settings.py b/radian/settings.py index 6b9d3d9..bfe0b5c 100644 --- a/radian/settings.py +++ b/radian/settings.py @@ -38,6 +38,7 @@ def _load_prompt(self): def load(self): self._load_setting("auto_suggest", True, bool) self._load_setting("emacs_bindings_in_vi_insert_mode", True, bool) + self._load_setting("tab_apply_completion", True, bool) self._load_setting("editing_mode", "emacs") self._load_setting("color_scheme", "native") self._load_setting("auto_match", True, bool) From f5bad69c457c5e827f7c64cb70c1e8232fab2b54 Mon Sep 17 00:00:00 2001 From: Martin Skarzynski Date: Sat, 10 Oct 2020 22:08:00 -0400 Subject: [PATCH 2/3] disable tab_apply_completion (tac) by default and rename as auto_complete_commit_on_tab (accot) --- radian/key_bindings.py | 24 ++++++++++++------------ radian/settings.py | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/radian/key_bindings.py b/radian/key_bindings.py index 8939ea3..05a3a65 100644 --- a/radian/key_bindings.py +++ b/radian/key_bindings.py @@ -413,8 +413,8 @@ def is_callable(text=""): return False @Condition - def tac(): - return settings.tab_apply_completion + def accot(): + return settings.auto_complete_commit_on_tab insert_mode = vi_insert_mode | emacs_insert_mode focused_insert = insert_mode & has_focus(DEFAULT_BUFFER) @@ -422,8 +422,8 @@ def tac(): alt_enter = [KeyPress(Keys.Escape), KeyPress(Keys.Enter)] # apply selected completion - @handle('c-j', filter=focused_insert & completion_is_selected & tac) - @handle("enter", filter=focused_insert & completion_is_selected & tac) + @handle('c-j', filter=focused_insert & completion_is_selected & accot) + @handle("enter", filter=focused_insert & completion_is_selected & accot) def _(event): b = event.current_buffer text = b.text @@ -435,8 +435,8 @@ def _(event): event.cli.key_processor.feed_multiple(alt_enter) # apply first completion option when completion menu is showing - @handle('c-j', filter=focused_insert & shown_not_selected & tac) - @handle("enter", filter=focused_insert & shown_not_selected & tac) + @handle('c-j', filter=focused_insert & shown_not_selected & accot) + @handle("enter", filter=focused_insert & shown_not_selected & accot) def _(event): b = event.current_buffer text = b.text @@ -449,8 +449,8 @@ def _(event): event.cli.key_processor.feed_multiple(alt_enter) # apply completion if there is only one option, otherwise start completion - @handle("tab", filter=focused_insert & ~has_completions & tac) - @handle("c-space", filter=focused_insert & ~has_completions & tac) + @handle("tab", filter=focused_insert & ~has_completions & accot) + @handle("c-space", filter=focused_insert & ~has_completions & accot) def _(event): b = event.current_buffer complete_event = CompleteEvent(completion_requested=True) @@ -465,8 +465,8 @@ def _(event): b.start_completion(insert_common_part=True) # apply first completion option if completion menu is showing - @handle("tab", filter=focused_insert & shown_not_selected & tac) - @handle("c-space", filter=focused_insert & shown_not_selected & tac) + @handle("tab", filter=focused_insert & shown_not_selected & accot) + @handle("c-space", filter=focused_insert & shown_not_selected & accot) def _(event): b = event.current_buffer b.complete_next() @@ -476,8 +476,8 @@ def _(event): b.cursor_left() # apply selected completion option - @handle("tab", filter=focused_insert & completion_is_selected & tac) - @handle("c-space", filter=focused_insert & completion_is_selected & tac) + @handle("tab", filter=focused_insert & completion_is_selected & accot) + @handle("c-space", filter=focused_insert & completion_is_selected & accot) def _(event): b = event.current_buffer completion = b.complete_state.current_completion diff --git a/radian/settings.py b/radian/settings.py index bfe0b5c..57c16f0 100644 --- a/radian/settings.py +++ b/radian/settings.py @@ -38,7 +38,7 @@ def _load_prompt(self): def load(self): self._load_setting("auto_suggest", True, bool) self._load_setting("emacs_bindings_in_vi_insert_mode", True, bool) - self._load_setting("tab_apply_completion", True, bool) + self._load_setting("auto_complete_commit_on_tab", False, bool) self._load_setting("editing_mode", "emacs") self._load_setting("color_scheme", "native") self._load_setting("auto_match", True, bool) From 52ba013570c02c53ea748b829509d13ddc985ebd Mon Sep 17 00:00:00 2001 From: Martin Skarzynski Date: Sat, 17 Oct 2020 20:08:43 -0400 Subject: [PATCH 3/3] add completion settings and improve completion bindings --- radian/key_bindings.py | 108 ++++++++++++++++++++++------------------- radian/settings.py | 6 ++- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/radian/key_bindings.py b/radian/key_bindings.py index 05a3a65..251c083 100644 --- a/radian/key_bindings.py +++ b/radian/key_bindings.py @@ -2,7 +2,6 @@ import re import os -from prompt_toolkit.completion import CompleteEvent from prompt_toolkit.application.current import get_app from prompt_toolkit.application.run_in_terminal import run_in_terminal from prompt_toolkit.eventloop import From, ensure_future @@ -413,78 +412,89 @@ def is_callable(text=""): return False @Condition - def accot(): - return settings.auto_complete_commit_on_tab + def auto_complete_selected_option_on_tab(): + return settings.auto_complete_selected_option_on_tab + + @Condition + def auto_complete_top_option_on_enter(): + return settings.auto_complete_top_option_on_enter + + @Condition + def auto_complete_top_option_on_tab(): + return settings.auto_complete_top_option_on_tab + + @Condition + def auto_complete_only_option_on_tab(): + return settings.auto_complete_only_option_on_tab insert_mode = vi_insert_mode | emacs_insert_mode focused_insert = insert_mode & has_focus(DEFAULT_BUFFER) shown_not_selected = has_completions & ~completion_is_selected - alt_enter = [KeyPress(Keys.Escape), KeyPress(Keys.Enter)] - # apply selected completion - @handle('c-j', filter=focused_insert & completion_is_selected & accot) - @handle("enter", filter=focused_insert & completion_is_selected & accot) + # apply selected completion option with enter + @handle('c-j', filter=focused_insert & completion_is_selected) + @handle("enter", filter=focused_insert & completion_is_selected) def _(event): b = event.current_buffer - text = b.text completion = b.complete_state.current_completion - if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): - b.insert_text("()") - b.cursor_left() - if text == b.text: - event.cli.key_processor.feed_multiple(alt_enter) + b.apply_completion(completion) + if settings.auto_complete_function_parentheses: + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() - # apply first completion option when completion menu is showing - @handle('c-j', filter=focused_insert & shown_not_selected & accot) - @handle("enter", filter=focused_insert & shown_not_selected & accot) + # apply selected completion option with tab + @handle("tab", filter=focused_insert & completion_is_selected & auto_complete_selected_option_on_tab) + @handle("c-space", filter=focused_insert & completion_is_selected & auto_complete_selected_option_on_tab) def _(event): b = event.current_buffer - text = b.text - b.complete_next() completion = b.complete_state.current_completion - if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): - b.insert_text("()") - b.cursor_left() - if text == b.text: - event.cli.key_processor.feed_multiple(alt_enter) + b.apply_completion(completion) + if settings.auto_complete_function_parentheses: + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() - # apply completion if there is only one option, otherwise start completion - @handle("tab", filter=focused_insert & ~has_completions & accot) - @handle("c-space", filter=focused_insert & ~has_completions & accot) + # apply first completion option with enter when completion menu is showing + @handle('c-j', filter=focused_insert & shown_not_selected & auto_complete_top_option_on_enter) + @handle("enter", filter=focused_insert & shown_not_selected & auto_complete_top_option_on_enter) def _(event): b = event.current_buffer - complete_event = CompleteEvent(completion_requested=True) - completions = list(b.completer.get_completions(b.document, complete_event)) - if len(completions) == 1: - completion = completions[0] - b.apply_completion(completion) + completion = b.complete_state.completions[0] + b.apply_completion(completion) + if settings.auto_complete_function_parentheses: if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): b.insert_text("()") b.cursor_left() - else: - b.start_completion(insert_common_part=True) - # apply first completion option if completion menu is showing - @handle("tab", filter=focused_insert & shown_not_selected & accot) - @handle("c-space", filter=focused_insert & shown_not_selected & accot) + # apply first completion option with tab if completion menu is showing + @handle("tab", filter=focused_insert & shown_not_selected & auto_complete_top_option_on_tab) + @handle("c-space", filter=focused_insert & shown_not_selected & auto_complete_top_option_on_tab) def _(event): b = event.current_buffer - b.complete_next() - completion = b.complete_state.current_completion - if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): - b.insert_text("()") - b.cursor_left() + completion = b.complete_state.completions[0] + b.apply_completion(completion) + if settings.auto_complete_function_parentheses: + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() - # apply selected completion option - @handle("tab", filter=focused_insert & completion_is_selected & accot) - @handle("c-space", filter=focused_insert & completion_is_selected & accot) + # apply completion if there is only one option, otherwise start completion + @handle("tab", filter=focused_insert & ~has_completions & auto_complete_only_option_on_tab) + @handle("c-space", filter=focused_insert & ~has_completions & auto_complete_only_option_on_tab) def _(event): b = event.current_buffer - completion = b.complete_state.current_completion - b.apply_completion(completion) - if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): - b.insert_text("()") - b.cursor_left() + b.start_completion() + completions = b.complete_state.completions + if len(completions) == 1: + completion = completions[0] + b.apply_completion(completion) + if settings.auto_complete_function_parentheses: + if is_callable(completion.text) or is_callable(b.document.get_word_under_cursor()): + b.insert_text("()") + b.cursor_left() + else: + b.start_completion(insert_common_part=True) # cancel completion @handle('c-c', filter=default_focused & has_completions) diff --git a/radian/settings.py b/radian/settings.py index 57c16f0..ec3cb3b 100644 --- a/radian/settings.py +++ b/radian/settings.py @@ -38,7 +38,11 @@ def _load_prompt(self): def load(self): self._load_setting("auto_suggest", True, bool) self._load_setting("emacs_bindings_in_vi_insert_mode", True, bool) - self._load_setting("auto_complete_commit_on_tab", False, bool) + self._load_setting("auto_complete_selected_option_on_tab", False, bool) + self._load_setting("auto_complete_top_option_on_tab", False, bool) + self._load_setting("auto_complete_only_option_on_tab", False, bool) + self._load_setting("auto_complete_top_option_on_enter", False, bool) + self._load_setting("auto_complete_function_parentheses", False, bool) self._load_setting("editing_mode", "emacs") self._load_setting("color_scheme", "native") self._load_setting("auto_match", True, bool)