First try at using cursor position
This commit is contained in:
parent
4d0649a825
commit
dc655dd40b
@ -65,6 +65,7 @@ class CompletionView(QTreeView):
|
|||||||
Signals:
|
Signals:
|
||||||
change_completed_part: Text which should be substituted for the word
|
change_completed_part: Text which should be substituted for the word
|
||||||
we're currently completing.
|
we're currently completing.
|
||||||
|
arg: The text to change to.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
STYLESHEET = """
|
STYLESHEET = """
|
||||||
@ -201,13 +202,16 @@ class CompletionView(QTreeView):
|
|||||||
# Item is a real item, not a category header -> success
|
# Item is a real item, not a category header -> success
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def _get_new_completion(self, parts):
|
def _get_new_completion(self, parts, cursor_part):
|
||||||
"""Get a new completion model.
|
"""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:
|
logger.debug("cursor part: {}".format(cursor_part))
|
||||||
# parts = [''] or something like ['set']
|
if cursor_part == 0:
|
||||||
|
# '|' or 'set|'
|
||||||
return self._models['command']
|
return self._models['command']
|
||||||
# delegate completion to command
|
# delegate completion to command
|
||||||
try:
|
try:
|
||||||
@ -220,19 +224,18 @@ class CompletionView(QTreeView):
|
|||||||
# command without any available completions
|
# command without any available completions
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
idx = len(parts[1:]) - 1
|
idx = cursor_part - 1
|
||||||
completion_name = completions[idx]
|
completion_name = completions[idx]
|
||||||
logger.debug('partlen: {}, modelname {}'.format(
|
logger.debug('modelname {}'.format(completion_name))
|
||||||
len(parts[1:]), completion_name))
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# More arguments than completions
|
# More arguments than completions
|
||||||
return None
|
return None
|
||||||
if completion_name == 'option':
|
if completion_name == 'option':
|
||||||
section = parts[-2]
|
section = parts[cursor_part - 1]
|
||||||
model = self._models['option'].get(section)
|
model = self._models['option'].get(section)
|
||||||
elif completion_name == 'value':
|
elif completion_name == 'value':
|
||||||
section = parts[-3]
|
section = parts[cursor_part - 2]
|
||||||
option = parts[-2]
|
option = parts[cursor_part - 1]
|
||||||
try:
|
try:
|
||||||
model = self._models['value'][section][option]
|
model = self._models['value'][section][option]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -249,9 +252,6 @@ class CompletionView(QTreeView):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
prev: True for prev item, False for next one.
|
prev: True for prev item, False for next one.
|
||||||
|
|
||||||
Emit:
|
|
||||||
change_completed_part: When a completion took place.
|
|
||||||
"""
|
"""
|
||||||
if not self._completing:
|
if not self._completing:
|
||||||
# No completion running at the moment, ignore keypress
|
# No completion running at the moment, ignore keypress
|
||||||
@ -283,16 +283,16 @@ class CompletionView(QTreeView):
|
|||||||
elif section == 'aliases':
|
elif section == 'aliases':
|
||||||
self._init_command_completion()
|
self._init_command_completion()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, int)
|
||||||
def on_update_completion(self, text):
|
def on_update_completion(self, text, cursor_part):
|
||||||
"""Check if completions are available and activate them.
|
"""Check if completions are available and activate them.
|
||||||
|
|
||||||
Slot for the textChanged signal of the statusbar command widget.
|
Slot for the textChanged signal of the statusbar command widget.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: The new text
|
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(':'):
|
if not text.startswith(':'):
|
||||||
# This is a search or gibberish, so we don't need to complete
|
# This is a search or gibberish, so we don't need to complete
|
||||||
# anything (yet)
|
# anything (yet)
|
||||||
@ -304,7 +304,7 @@ class CompletionView(QTreeView):
|
|||||||
text = text.lstrip(':')
|
text = text.lstrip(':')
|
||||||
parts = split_cmdline(text)
|
parts = split_cmdline(text)
|
||||||
|
|
||||||
model = self._get_new_completion(parts)
|
model = self._get_new_completion(parts, cursor_part)
|
||||||
if model is None:
|
if model is None:
|
||||||
logger.debug("No completion model for {}.".format(parts))
|
logger.debug("No completion model for {}.".format(parts))
|
||||||
else:
|
else:
|
||||||
@ -324,7 +324,8 @@ class CompletionView(QTreeView):
|
|||||||
if model is None:
|
if model is None:
|
||||||
return
|
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.pattern = pattern
|
||||||
self._model.srcmodel.mark_all_items(pattern)
|
self._model.srcmodel.mark_all_items(pattern)
|
||||||
if self._enabled:
|
if self._enabled:
|
||||||
|
@ -50,7 +50,8 @@ class Command(MinimalLineEdit):
|
|||||||
hidden.
|
hidden.
|
||||||
hide_completion: Emitted when the completion widget should be hidden.
|
hide_completion: Emitted when the completion widget should be hidden.
|
||||||
update_completion: Emitted when the completion should be shown/updated.
|
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.
|
show_cmd: Emitted when command input should be shown.
|
||||||
hide_cmd: Emitted when command input can be hidden.
|
hide_cmd: Emitted when command input can be hidden.
|
||||||
"""
|
"""
|
||||||
@ -60,7 +61,7 @@ class Command(MinimalLineEdit):
|
|||||||
got_search_rev = pyqtSignal(str)
|
got_search_rev = pyqtSignal(str)
|
||||||
clear_completion_selection = pyqtSignal()
|
clear_completion_selection = pyqtSignal()
|
||||||
hide_completion = pyqtSignal()
|
hide_completion = pyqtSignal()
|
||||||
update_completion = pyqtSignal(str)
|
update_completion = pyqtSignal(str, int)
|
||||||
show_cmd = pyqtSignal()
|
show_cmd = pyqtSignal()
|
||||||
hide_cmd = pyqtSignal()
|
hide_cmd = pyqtSignal()
|
||||||
|
|
||||||
@ -73,10 +74,35 @@ class Command(MinimalLineEdit):
|
|||||||
self.history = History()
|
self.history = History()
|
||||||
self._validator = _CommandValidator(self)
|
self._validator = _CommandValidator(self)
|
||||||
self.setValidator(self._validator)
|
self.setValidator(self._validator)
|
||||||
self.textEdited.connect(self.history.stop)
|
self.textEdited.connect(self.on_text_edited)
|
||||||
self.textEdited.connect(self.update_completion)
|
self.cursorPositionChanged.connect(self.on_cursor_position_changed)
|
||||||
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
|
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)
|
@pyqtSlot(str)
|
||||||
def set_cmd_text(self, text):
|
def set_cmd_text(self, text):
|
||||||
"""Preset the statusbar to some text.
|
"""Preset the statusbar to some text.
|
||||||
@ -91,7 +117,7 @@ class Command(MinimalLineEdit):
|
|||||||
self.setText(text)
|
self.setText(text)
|
||||||
if old_text != text:
|
if old_text != text:
|
||||||
# We want the completion to pop out here.
|
# We want the completion to pop out here.
|
||||||
self.update_completion.emit(text)
|
self.update_completion.emit(text, self._cursor_part())
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
self.show_cmd.emit()
|
self.show_cmd.emit()
|
||||||
|
|
||||||
@ -102,18 +128,14 @@ class Command(MinimalLineEdit):
|
|||||||
Args:
|
Args:
|
||||||
text: The text to set (string).
|
text: The text to set (string).
|
||||||
"""
|
"""
|
||||||
# FIXME we should consider the cursor position.
|
prefix, parts = self._split()
|
||||||
text = self.text()
|
cursor_part = self._cursor_part()
|
||||||
if text[0] in STARTCHARS:
|
logger.debug("parts: {}, changing {} to '{}'".format(
|
||||||
prefix = text[0]
|
parts, cursor_part, newtext))
|
||||||
text = text[1:]
|
parts[cursor_part] = newtext
|
||||||
else:
|
self.blockSignals(True)
|
||||||
prefix = ''
|
|
||||||
parts = split_cmdline(text)
|
|
||||||
logger.debug("Old text: '{}' - parts: {}, changing to '{}'".format(
|
|
||||||
text, parts, newtext))
|
|
||||||
parts[-1] = newtext
|
|
||||||
self.setText(prefix + ' '.join(parts))
|
self.setText(prefix + ' '.join(parts))
|
||||||
|
self.blockSignals(False)
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
self.show_cmd.emit()
|
self.show_cmd.emit()
|
||||||
|
|
||||||
@ -165,6 +187,17 @@ class Command(MinimalLineEdit):
|
|||||||
if text[0] in signals:
|
if text[0] in signals:
|
||||||
signals[text[0]].emit(text.lstrip(text[0]))
|
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):
|
def on_mode_left(self, mode):
|
||||||
"""Clear up when ommand mode was left.
|
"""Clear up when ommand mode was left.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user