Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide option to have tab apply completion #229

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 92 additions & 5 deletions radian/key_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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, \
Expand All @@ -20,7 +21,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

Expand Down Expand Up @@ -403,11 +404,97 @@ 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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is a robust way to detect if a token is a function. We may need to poke into how the token is determined: https://github.com/randy3k/rchitect/blob/master/rchitect/completion.py#L18

Copy link
Author

@mskar mskar Oct 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this part of the code could be improved, but so far the parentheses are added without fail. In other words, I have not found a situation in which this doesn't work.
I can't find much in the way of documentation on completeToken. It is used by the completeme package. I looked at the source code for completeToken and it seems like completeToken guesses which function it is inside for argument completion, but I don't know how this might help us to identify the token as a function.
I'm hoping that you might have some ideas regarding the best way to determine if a token is a function😄


@Condition
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

# 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
completion = b.complete_state.current_completion
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 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):
event.current_buffer.complete_state = None
b = event.current_buffer
completion = b.complete_state.current_completion
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 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
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 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
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 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
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)
Expand Down
5 changes: 5 additions & 0 deletions radian/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +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_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)
Expand Down