Skip to content

Commit 4bfc18d

Browse files
committed
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. `<html[cursor]` -> `<html>[cursor]</html>`.
1 parent 117eaff commit 4bfc18d

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python
2+
"""
3+
Autocompletion example with cursor position not at the end of the completion.
4+
5+
Press [Tab] to complete the current word.
6+
- The first Tab press fills in the common part of all completions
7+
and shows all the completions. (In the menu)
8+
- Any following tab press cycles through all the possible completions.
9+
"""
10+
from __future__ import unicode_literals
11+
from collections import namedtuple
12+
13+
from prompt_toolkit import prompt, completion
14+
from prompt_toolkit.completion import Completer, Completion
15+
16+
CompletionWithCursorPosition = namedtuple('CompletionWithCursorPosition',
17+
'text cursor_position')
18+
19+
class CursorPositionCompleter(Completer):
20+
"""
21+
Simple autocompletion on a list of words with associated cursor positions.
22+
23+
:param completions: List of CompletionWithCursorPosition namedtuples.
24+
"""
25+
def __init__(self, completions):
26+
self.completions = completions
27+
28+
def get_completions(self, document, complete_event):
29+
before_cursor = document.get_word_before_cursor()
30+
return (Completion(c.text, -len(before_cursor), cursor_position=c.cursor_position)
31+
for c in self.completions
32+
if c.text.startswith(before_cursor))
33+
34+
completions = {
35+
CompletionWithCursorPosition('upper_case()', 1),
36+
CompletionWithCursorPosition('lower_case()', 1),
37+
CompletionWithCursorPosition('list_add(list:=, element:=)', len(', element:=)')),
38+
CompletionWithCursorPosition('<html></html>', len('</html>'))
39+
}
40+
41+
comp = CursorPositionCompleter(completions)
42+
43+
def main():
44+
text = prompt('Input: ', completer=comp,
45+
complete_while_typing=False)
46+
print('You said: %s' % text)
47+
48+
49+
if __name__ == '__main__':
50+
main()

prompt_toolkit/buffer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def new_text_and_position(self):
137137
before = original_text_before_cursor[:c.start_position]
138138

139139
new_text = before + c.text + original_text_after_cursor
140-
new_cursor_position = len(before) + len(c.text)
140+
new_cursor_position = len(before) + len(c.text) - c.cursor_position
141141
return new_text, new_cursor_position
142142

143143
@property

prompt_toolkit/completion.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ class Completion(object):
2424
completion, e.g. the path or source where it's coming from.
2525
:param get_display_meta: Lazy `display_meta`. Retrieve meta information
2626
only when meta is displayed.
27+
:param cursor_position: Cursor position after completion, from end
2728
"""
2829
def __init__(self, text, start_position=0, display=None, display_meta=None,
29-
get_display_meta=None):
30+
get_display_meta=None, cursor_position=0):
3031
self.text = text
3132
self.start_position = start_position
3233
self._display_meta = display_meta
3334
self._get_display_meta = get_display_meta
35+
self.cursor_position = cursor_position
3436

3537
if display is None:
3638
self.display = text

prompt_toolkit/interface.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,8 @@ def callback():
804804
if common_part:
805805
# Insert + run completer again.
806806
buffer.insert_text(common_part)
807+
if len(completions) == 1:
808+
buffer.cursor_position -= completions[0].cursor_position
807809
async_completer()
808810
set_completions = False
809811
else:

0 commit comments

Comments
 (0)