From 4bfc18d5869cc1d23347a816bd833c13e227df93 Mon Sep 17 00:00:00 2001 From: koljonen Date: Fri, 17 Jun 2016 18:04:14 +0200 Subject: [PATCH] Add cursor_position property to Completion `cursor_position` says how far from the end of the completion the cursor should be placed, so that we can have completions such as e.g. ` `[cursor]`. --- .../autocompletion-with-cursor-position.py | 50 +++++++++++++++++++ prompt_toolkit/buffer.py | 2 +- prompt_toolkit/completion.py | 4 +- prompt_toolkit/interface.py | 2 + 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100755 examples/autocompletion-with-cursor-position.py diff --git a/examples/autocompletion-with-cursor-position.py b/examples/autocompletion-with-cursor-position.py new file mode 100755 index 0000000000..69e84ae738 --- /dev/null +++ b/examples/autocompletion-with-cursor-position.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +""" +Autocompletion example with cursor position not at the end of the completion. + +Press [Tab] to complete the current word. +- The first Tab press fills in the common part of all completions + and shows all the completions. (In the menu) +- Any following tab press cycles through all the possible completions. +""" +from __future__ import unicode_literals +from collections import namedtuple + +from prompt_toolkit import prompt, completion +from prompt_toolkit.completion import Completer, Completion + +CompletionWithCursorPosition = namedtuple('CompletionWithCursorPosition', + 'text cursor_position') + +class CursorPositionCompleter(Completer): + """ + Simple autocompletion on a list of words with associated cursor positions. + + :param completions: List of CompletionWithCursorPosition namedtuples. + """ + def __init__(self, completions): + self.completions = completions + + def get_completions(self, document, complete_event): + before_cursor = document.get_word_before_cursor() + return (Completion(c.text, -len(before_cursor), cursor_position=c.cursor_position) + for c in self.completions + if c.text.startswith(before_cursor)) + +completions = { + CompletionWithCursorPosition('upper_case()', 1), + CompletionWithCursorPosition('lower_case()', 1), + CompletionWithCursorPosition('list_add(list:=, element:=)', len(', element:=)')), + CompletionWithCursorPosition('', len('')) +} + +comp = CursorPositionCompleter(completions) + +def main(): + text = prompt('Input: ', completer=comp, + complete_while_typing=False) + print('You said: %s' % text) + + +if __name__ == '__main__': + main() diff --git a/prompt_toolkit/buffer.py b/prompt_toolkit/buffer.py index 739486a498..6d6b917949 100644 --- a/prompt_toolkit/buffer.py +++ b/prompt_toolkit/buffer.py @@ -137,7 +137,7 @@ def new_text_and_position(self): before = original_text_before_cursor[:c.start_position] new_text = before + c.text + original_text_after_cursor - new_cursor_position = len(before) + len(c.text) + new_cursor_position = len(before) + len(c.text) - c.cursor_position return new_text, new_cursor_position @property diff --git a/prompt_toolkit/completion.py b/prompt_toolkit/completion.py index 056274a136..70ef6dee48 100644 --- a/prompt_toolkit/completion.py +++ b/prompt_toolkit/completion.py @@ -24,13 +24,15 @@ class Completion(object): completion, e.g. the path or source where it's coming from. :param get_display_meta: Lazy `display_meta`. Retrieve meta information only when meta is displayed. + :param cursor_position: Cursor position after completion, from end """ def __init__(self, text, start_position=0, display=None, display_meta=None, - get_display_meta=None): + get_display_meta=None, cursor_position=0): self.text = text self.start_position = start_position self._display_meta = display_meta self._get_display_meta = get_display_meta + self.cursor_position = cursor_position if display is None: self.display = text diff --git a/prompt_toolkit/interface.py b/prompt_toolkit/interface.py index 78993c374b..849830660b 100644 --- a/prompt_toolkit/interface.py +++ b/prompt_toolkit/interface.py @@ -804,6 +804,8 @@ def callback(): if common_part: # Insert + run completer again. buffer.insert_text(common_part) + if len(completions) == 1: + buffer.cursor_position -= completions[0].cursor_position async_completer() set_completions = False else: