First try at using cursor position

This commit is contained in:
Florian Bruhin 2014-05-27 17:21:29 +02:00
parent 4d0649a825
commit dc655dd40b
2 changed files with 68 additions and 34 deletions

View File

@ -65,6 +65,7 @@ class CompletionView(QTreeView):
Signals:
change_completed_part: Text which should be substituted for the word
we're currently completing.
arg: The text to change to.
"""
STYLESHEET = """
@ -201,13 +202,16 @@ class CompletionView(QTreeView):
# Item is a real item, not a category header -> success
return idx
def _get_new_completion(self, parts):
def _get_new_completion(self, parts, cursor_part):
"""Get a new completion model.
parts: The command chunks to get a completion for.
Args:
parts: The command chunks to get a completion for.
cursor_part: The part the cursor is over currently.
"""
if len(parts) == 1:
# parts = [''] or something like ['set']
logger.debug("cursor part: {}".format(cursor_part))
if cursor_part == 0:
# '|' or 'set|'
return self._models['command']
# delegate completion to command
try:
@ -220,19 +224,18 @@ class CompletionView(QTreeView):
# command without any available completions
return None
try:
idx = len(parts[1:]) - 1
idx = cursor_part - 1
completion_name = completions[idx]
logger.debug('partlen: {}, modelname {}'.format(
len(parts[1:]), completion_name))
logger.debug('modelname {}'.format(completion_name))
except IndexError:
# More arguments than completions
return None
if completion_name == 'option':
section = parts[-2]
section = parts[cursor_part - 1]
model = self._models['option'].get(section)
elif completion_name == 'value':
section = parts[-3]
option = parts[-2]
section = parts[cursor_part - 2]
option = parts[cursor_part - 1]
try:
model = self._models['value'][section][option]
except KeyError:
@ -249,9 +252,6 @@ class CompletionView(QTreeView):
Args:
prev: True for prev item, False for next one.
Emit:
change_completed_part: When a completion took place.
"""
if not self._completing:
# No completion running at the moment, ignore keypress
@ -283,16 +283,16 @@ class CompletionView(QTreeView):
elif section == 'aliases':
self._init_command_completion()
@pyqtSlot(str)
def on_update_completion(self, text):
@pyqtSlot(str, int)
def on_update_completion(self, text, cursor_part):
"""Check if completions are available and activate them.
Slot for the textChanged signal of the statusbar command widget.
Args:
text: The new text
cursor_part: The part the cursor is currently over.
"""
# FIXME we should also consider the cursor position
if not text.startswith(':'):
# This is a search or gibberish, so we don't need to complete
# anything (yet)
@ -304,7 +304,7 @@ class CompletionView(QTreeView):
text = text.lstrip(':')
parts = split_cmdline(text)
model = self._get_new_completion(parts)
model = self._get_new_completion(parts, cursor_part)
if model is None:
logger.debug("No completion model for {}.".format(parts))
else:
@ -324,7 +324,8 @@ class CompletionView(QTreeView):
if model is None:
return
pattern = parts[-1] if parts else ''
pattern = parts[cursor_part] if parts else ''
logger.debug("pattern: {}".format(pattern))
self._model.pattern = pattern
self._model.srcmodel.mark_all_items(pattern)
if self._enabled:

View File

@ -50,7 +50,8 @@ class Command(MinimalLineEdit):
hidden.
hide_completion: Emitted when the completion widget should be hidden.
update_completion: Emitted when the completion should be shown/updated.
arg: The new text which was set.
arg 0: The new text which was set.
arg 1: The part the cursor is currently in.
show_cmd: Emitted when command input should be shown.
hide_cmd: Emitted when command input can be hidden.
"""
@ -60,7 +61,7 @@ class Command(MinimalLineEdit):
got_search_rev = pyqtSignal(str)
clear_completion_selection = pyqtSignal()
hide_completion = pyqtSignal()
update_completion = pyqtSignal(str)
update_completion = pyqtSignal(str, int)
show_cmd = pyqtSignal()
hide_cmd = pyqtSignal()
@ -73,10 +74,35 @@ class Command(MinimalLineEdit):
self.history = History()
self._validator = _CommandValidator(self)
self.setValidator(self._validator)
self.textEdited.connect(self.history.stop)
self.textEdited.connect(self.update_completion)
self.textEdited.connect(self.on_text_edited)
self.cursorPositionChanged.connect(self.on_cursor_position_changed)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
def _cursor_part(self):
"""Get the part index of the commandline where the cursor is over."""
prefix, parts = self._split()
cursor_pos = self.cursorPosition()
cursor_pos -= len(prefix)
for i, part in enumerate(parts):
logger.debug("part {}, len {}, pos {}".format(i, len(part),
cursor_pos))
if cursor_pos <= len(part):
# foo| bar
return i
cursor_pos -= (len(part) + 1) # FIXME are spaces always 1 char?
def _split(self):
text = self.text()
if not text:
return '', []
if text[0] in STARTCHARS:
prefix = text[0]
text = text[1:]
else:
prefix = ''
parts = split_cmdline(text)
return prefix, parts
@pyqtSlot(str)
def set_cmd_text(self, text):
"""Preset the statusbar to some text.
@ -91,7 +117,7 @@ class Command(MinimalLineEdit):
self.setText(text)
if old_text != text:
# We want the completion to pop out here.
self.update_completion.emit(text)
self.update_completion.emit(text, self._cursor_part())
self.setFocus()
self.show_cmd.emit()
@ -102,18 +128,14 @@ class Command(MinimalLineEdit):
Args:
text: The text to set (string).
"""
# FIXME we should consider the cursor position.
text = self.text()
if text[0] in STARTCHARS:
prefix = text[0]
text = text[1:]
else:
prefix = ''
parts = split_cmdline(text)
logger.debug("Old text: '{}' - parts: {}, changing to '{}'".format(
text, parts, newtext))
parts[-1] = newtext
prefix, parts = self._split()
cursor_part = self._cursor_part()
logger.debug("parts: {}, changing {} to '{}'".format(
parts, cursor_part, newtext))
parts[cursor_part] = newtext
self.blockSignals(True)
self.setText(prefix + ' '.join(parts))
self.blockSignals(False)
self.setFocus()
self.show_cmd.emit()
@ -165,6 +187,17 @@ class Command(MinimalLineEdit):
if text[0] in signals:
signals[text[0]].emit(text.lstrip(text[0]))
@pyqtSlot(str)
def on_text_edited(self, text):
"""Slot for textEdited. Stop history and update completion."""
self.history.stop()
self.update_completion.emit(text, self._cursor_part())
@pyqtSlot(int, int)
def on_cursor_position_changed(self, _old, _new):
"""Slot for cursorPositionChanged to update completion."""
self.update_completion.emit(self.text(), self._cursor_part())
def on_mode_left(self, mode):
"""Clear up when ommand mode was left.