parent
5e7ef5201c
commit
d71147898b
@ -19,10 +19,10 @@
|
|||||||
|
|
||||||
"""Completer attached to a CompletionView."""
|
"""Completer attached to a CompletionView."""
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer
|
from PyQt5.QtCore import pyqtSlot, QObject, QTimer
|
||||||
|
|
||||||
from qutebrowser.config import config, configdata
|
from qutebrowser.config import config, configdata
|
||||||
from qutebrowser.commands import cmdutils
|
from qutebrowser.commands import cmdutils, runners
|
||||||
from qutebrowser.utils import usertypes, log, objreg, utils
|
from qutebrowser.utils import usertypes, log, objreg, utils
|
||||||
from qutebrowser.models import completion as models
|
from qutebrowser.models import completion as models
|
||||||
from qutebrowser.models.completionfilter import CompletionFilterModel as CFM
|
from qutebrowser.models.completionfilter import CompletionFilterModel as CFM
|
||||||
@ -33,29 +33,22 @@ class Completer(QObject):
|
|||||||
"""Completer which manages completions in a CompletionView.
|
"""Completer which manages completions in a CompletionView.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_ignore_change: Whether to ignore the next completion update.
|
|
||||||
models: dict of available completion models.
|
models: dict of available completion models.
|
||||||
|
_cmd: The statusbar Command object this completer belongs to.
|
||||||
|
_ignore_change: Whether to ignore the next completion update.
|
||||||
_win_id: The window ID this completer is in.
|
_win_id: The window ID this completer is in.
|
||||||
_timer: The timer used to trigger the completion update.
|
_timer: The timer used to trigger the completion update.
|
||||||
_prefix: The prefix to be used for the next completion update.
|
|
||||||
_parts: The parts to be used for the next completion update.
|
|
||||||
_cursor_part: The cursor part index for the next completion update.
|
_cursor_part: The cursor part index for the next completion update.
|
||||||
|
|
||||||
Signals:
|
|
||||||
change_completed_part: Text which should be substituted for the word
|
|
||||||
we're currently completing.
|
|
||||||
arg 0: The text to change to.
|
|
||||||
arg 1: True if the text should be set
|
|
||||||
immediately, without continuing
|
|
||||||
completing the current field.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
change_completed_part = pyqtSignal(str, bool)
|
def __init__(self, cmd, win_id, parent=None):
|
||||||
|
|
||||||
def __init__(self, win_id, parent=None):
|
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
|
self._cmd = cmd
|
||||||
|
self._cmd.update_completion.connect(self.schedule_completion_update)
|
||||||
|
self._cmd.textEdited.connect(self.on_text_edited)
|
||||||
self._ignore_change = False
|
self._ignore_change = False
|
||||||
|
self._empty_item_idx = None
|
||||||
|
|
||||||
self._models = {
|
self._models = {
|
||||||
usertypes.Completion.option: {},
|
usertypes.Completion.option: {},
|
||||||
@ -68,8 +61,6 @@ class Completer(QObject):
|
|||||||
self._timer.setSingleShot(True)
|
self._timer.setSingleShot(True)
|
||||||
self._timer.setInterval(0)
|
self._timer.setInterval(0)
|
||||||
self._timer.timeout.connect(self.update_completion)
|
self._timer.timeout.connect(self.update_completion)
|
||||||
self._prefix = None
|
|
||||||
self._parts = None
|
|
||||||
self._cursor_part = None
|
self._cursor_part = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -224,7 +215,7 @@ class Completer(QObject):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def selection_changed(self, selected, _deselected):
|
def selection_changed(self, selected, _deselected):
|
||||||
"""Emit change_completed_part if a new item was selected.
|
"""Change the completed part if a new item was selected.
|
||||||
|
|
||||||
Called from the views selectionChanged method.
|
Called from the views selectionChanged method.
|
||||||
|
|
||||||
@ -243,39 +234,30 @@ class Completer(QObject):
|
|||||||
if model.count() == 1 and config.get('completion', 'quick-complete'):
|
if model.count() == 1 and config.get('completion', 'quick-complete'):
|
||||||
# If we only have one item, we want to apply it immediately
|
# If we only have one item, we want to apply it immediately
|
||||||
# and go on to the next part.
|
# and go on to the next part.
|
||||||
self.change_completed_part.emit(data, True)
|
self.change_completed_part(data, immediate=True)
|
||||||
else:
|
else:
|
||||||
self._ignore_change = True
|
self._ignore_change = True
|
||||||
self.change_completed_part.emit(data, False)
|
self.change_completed_part(data)
|
||||||
|
|
||||||
@pyqtSlot(str, list, int)
|
@pyqtSlot()
|
||||||
def on_update_completion(self, prefix, parts, cursor_part):
|
def schedule_completion_update(self):
|
||||||
"""Schedule updating/enabling completion.
|
"""Schedule updating/enabling completion.
|
||||||
|
|
||||||
Slot for the textChanged signal of the statusbar command widget.
|
|
||||||
|
|
||||||
For performance reasons we don't want to block here, instead we do this
|
For performance reasons we don't want to block here, instead we do this
|
||||||
in the background.
|
in the background.
|
||||||
"""
|
"""
|
||||||
|
log.completion.debug("Scheduling completion update.")
|
||||||
self._timer.start()
|
self._timer.start()
|
||||||
log.completion.debug("Scheduling completion update. prefix {}, parts "
|
|
||||||
"{}, cursor_part {}".format(prefix, parts,
|
|
||||||
cursor_part))
|
|
||||||
self._prefix = prefix
|
|
||||||
self._parts = parts
|
|
||||||
self._cursor_part = cursor_part
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def update_completion(self):
|
def update_completion(self):
|
||||||
"""Check if completions are available and activate them."""
|
"""Check if completions are available and activate them."""
|
||||||
|
self.update_cursor_part()
|
||||||
|
parts = self.split()
|
||||||
|
|
||||||
assert self._prefix is not None
|
log.completion.debug(
|
||||||
assert self._parts is not None
|
"Updating completion - prefix {}, parts {}, cursor_part {}".format(
|
||||||
assert self._cursor_part is not None
|
self._cmd.prefix(), parts, self._cursor_part))
|
||||||
|
|
||||||
log.completion.debug("Updating completion - prefix {}, parts {}, "
|
|
||||||
"cursor_part {}".format(self._prefix, self._parts,
|
|
||||||
self._cursor_part))
|
|
||||||
if self._ignore_change:
|
if self._ignore_change:
|
||||||
self._ignore_change = False
|
self._ignore_change = False
|
||||||
log.completion.debug("Ignoring completion update")
|
log.completion.debug("Ignoring completion update")
|
||||||
@ -284,7 +266,7 @@ class Completer(QObject):
|
|||||||
completion = objreg.get('completion', scope='window',
|
completion = objreg.get('completion', scope='window',
|
||||||
window=self._win_id)
|
window=self._win_id)
|
||||||
|
|
||||||
if self._prefix != ':':
|
if self._cmd.prefix() != ':':
|
||||||
# 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)
|
||||||
# FIXME complete searchs
|
# FIXME complete searchs
|
||||||
@ -292,7 +274,7 @@ class Completer(QObject):
|
|||||||
completion.hide()
|
completion.hide()
|
||||||
return
|
return
|
||||||
|
|
||||||
model = self._get_new_completion(self._parts, self._cursor_part)
|
model = self._get_new_completion(parts, self._cursor_part)
|
||||||
|
|
||||||
if model != self._model():
|
if model != self._model():
|
||||||
if model is None:
|
if model is None:
|
||||||
@ -301,19 +283,18 @@ class Completer(QObject):
|
|||||||
completion.set_model(model)
|
completion.set_model(model)
|
||||||
|
|
||||||
if model is None:
|
if model is None:
|
||||||
log.completion.debug("No completion model for {}.".format(
|
log.completion.debug("No completion model for {}.".format(parts))
|
||||||
self._parts))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pattern = self._parts[self._cursor_part].strip()
|
pattern = parts[self._cursor_part].strip()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pattern = ''
|
pattern = ''
|
||||||
self._model().set_pattern(pattern)
|
self._model().set_pattern(pattern)
|
||||||
|
|
||||||
log.completion.debug(
|
log.completion.debug(
|
||||||
"New completion for {}: {}, with pattern '{}'".format(
|
"New completion for {}: {}, with pattern '{}'".format(
|
||||||
self._parts, model.srcmodel.__class__.__name__, pattern))
|
parts, model.srcmodel.__class__.__name__, pattern))
|
||||||
|
|
||||||
if self._model().count() == 0:
|
if self._model().count() == 0:
|
||||||
completion.hide()
|
completion.hide()
|
||||||
@ -321,3 +302,114 @@ class Completer(QObject):
|
|||||||
|
|
||||||
if completion.enabled:
|
if completion.enabled:
|
||||||
completion.show()
|
completion.show()
|
||||||
|
|
||||||
|
def split(self, keep=False):
|
||||||
|
"""Get the text split up in parts.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
keep: Whether to keep special chars and whitespace.
|
||||||
|
"""
|
||||||
|
text = self._cmd.text()[len(self._cmd.prefix()):]
|
||||||
|
if not text:
|
||||||
|
# When only ":" is entered, we already have one imaginary part,
|
||||||
|
# which just is empty at the moment.
|
||||||
|
return ['']
|
||||||
|
if not text.strip():
|
||||||
|
# Text is only whitespace so we treat this as a single element with
|
||||||
|
# the whitespace.
|
||||||
|
return [text]
|
||||||
|
runner = runners.CommandRunner(self._win_id)
|
||||||
|
parts = runner.parse(text, fallback=True, alias_no_args=False,
|
||||||
|
keep=keep)
|
||||||
|
if self._empty_item_idx is not None:
|
||||||
|
log.completion.debug("Empty element queued at {}, "
|
||||||
|
"inserting.".format(self._empty_item_idx))
|
||||||
|
parts.insert(self._empty_item_idx, '')
|
||||||
|
#log.completion.debug("Splitting '{}' -> {}".format(text, parts))
|
||||||
|
return parts
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def update_cursor_part(self):
|
||||||
|
"""Get the part index of the commandline where the cursor is over."""
|
||||||
|
cursor_pos = self._cmd.cursorPosition()
|
||||||
|
snippet = slice(cursor_pos - 1, cursor_pos + 1)
|
||||||
|
if self._cmd.text()[snippet] == ' ':
|
||||||
|
spaces = True
|
||||||
|
else:
|
||||||
|
spaces = False
|
||||||
|
cursor_pos -= len(self._cmd.prefix())
|
||||||
|
parts = self.split(keep=True)
|
||||||
|
log.completion.vdebug(
|
||||||
|
"text: {}, parts: {}, cursor_pos after removing prefix '{}': "
|
||||||
|
"{}".format(self._cmd.text(), parts, self._cmd.prefix(),
|
||||||
|
cursor_pos))
|
||||||
|
for i, part in enumerate(parts):
|
||||||
|
log.completion.vdebug("Checking part {}: {}".format(i, parts[i]))
|
||||||
|
if cursor_pos <= len(part):
|
||||||
|
# foo| bar
|
||||||
|
self._cursor_part = i
|
||||||
|
if spaces:
|
||||||
|
self._empty_item_idx = i
|
||||||
|
else:
|
||||||
|
self._empty_item_idx = None
|
||||||
|
log.completion.vdebug("cursor_pos {} <= len(part) {}, "
|
||||||
|
"setting cursor_part {}, empty_item_idx "
|
||||||
|
"{}".format(cursor_pos, len(part), i,
|
||||||
|
self._empty_item_idx))
|
||||||
|
break
|
||||||
|
cursor_pos -= len(part)
|
||||||
|
log.completion.vdebug(
|
||||||
|
"Removing len({!r}) -> {} from cursor_pos -> {}".format(
|
||||||
|
part, len(part), cursor_pos))
|
||||||
|
else:
|
||||||
|
self._cursor_part = i
|
||||||
|
if spaces:
|
||||||
|
self._empty_item_idx = i
|
||||||
|
else:
|
||||||
|
self._empty_item_idx = None
|
||||||
|
log.completion.debug("cursor_part {}, spaces {}".format(
|
||||||
|
self._cursor_part, spaces))
|
||||||
|
return
|
||||||
|
|
||||||
|
def change_completed_part(self, newtext, immediate=False):
|
||||||
|
"""Change the part we're currently completing in the commandline.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: The text to set (string).
|
||||||
|
immediate: True if the text should be completed immediately
|
||||||
|
including a trailing space and we shouldn't continue
|
||||||
|
completing the current item.
|
||||||
|
"""
|
||||||
|
parts = self.split()
|
||||||
|
log.completion.debug("changing part {} to '{}'".format(
|
||||||
|
self._cursor_part, newtext))
|
||||||
|
try:
|
||||||
|
parts[self._cursor_part] = newtext
|
||||||
|
except IndexError:
|
||||||
|
parts.append(newtext)
|
||||||
|
# We want to place the cursor directly after the part we just changed.
|
||||||
|
cursor_str = self._cmd.prefix() + ' '.join(
|
||||||
|
parts[:self._cursor_part + 1])
|
||||||
|
if immediate:
|
||||||
|
# If we should complete immediately, we want to move the cursor by
|
||||||
|
# one more char, to get to the next field.
|
||||||
|
cursor_str += ' '
|
||||||
|
text = self._cmd.prefix() + ' '.join(parts)
|
||||||
|
if immediate and self._cursor_part == len(parts) - 1:
|
||||||
|
# If we should complete immediately and we're completing the last
|
||||||
|
# part in the commandline, we automatically add a space.
|
||||||
|
text += ' '
|
||||||
|
self._cmd.setText(text)
|
||||||
|
log.completion.debug("Placing cursor after '{}'".format(cursor_str))
|
||||||
|
log.modes.debug("Completion triggered, focusing {!r}".format(self))
|
||||||
|
self._cmd.setCursorPosition(len(cursor_str))
|
||||||
|
self._cmd.setFocus()
|
||||||
|
self._cmd.show_cmd.emit()
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def on_text_edited(self):
|
||||||
|
"""Reset _empty_item_idx if text was edited."""
|
||||||
|
self._empty_item_idx = None
|
||||||
|
# We also want to update the cursor part and emit update_completion
|
||||||
|
# here, but that's already done for us by cursorPositionChanged
|
||||||
|
# anyways, so we don't need to do it twice.
|
||||||
|
@ -93,7 +93,8 @@ class CompletionView(QTreeView):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
objreg.register('completion', self, scope='window', window=win_id)
|
objreg.register('completion', self, scope='window', window=win_id)
|
||||||
completer_obj = completer.Completer(win_id, self)
|
cmd = objreg.get('status-command', scope='window', window=win_id)
|
||||||
|
completer_obj = completer.Completer(cmd, win_id, self)
|
||||||
objreg.register('completer', completer_obj, scope='window',
|
objreg.register('completer', completer_obj, scope='window',
|
||||||
window=win_id)
|
window=win_id)
|
||||||
self.enabled = config.get('completion', 'show')
|
self.enabled = config.get('completion', 'show')
|
||||||
|
@ -91,11 +91,11 @@ class MainWindow(QWidget):
|
|||||||
window=win_id)
|
window=win_id)
|
||||||
self._vbox.addWidget(self._tabbed_browser)
|
self._vbox.addWidget(self._tabbed_browser)
|
||||||
|
|
||||||
self._completion = completion.CompletionView(win_id, self)
|
|
||||||
|
|
||||||
self.status = bar.StatusBar(win_id)
|
self.status = bar.StatusBar(win_id)
|
||||||
self._vbox.addWidget(self.status)
|
self._vbox.addWidget(self.status)
|
||||||
|
|
||||||
|
self._completion = completion.CompletionView(win_id, self)
|
||||||
|
|
||||||
self._commandrunner = runners.CommandRunner(win_id)
|
self._commandrunner = runners.CommandRunner(win_id)
|
||||||
|
|
||||||
log.init.debug("Initializing search...")
|
log.init.debug("Initializing search...")
|
||||||
@ -256,8 +256,6 @@ class MainWindow(QWidget):
|
|||||||
cmd.clear_completion_selection.connect(
|
cmd.clear_completion_selection.connect(
|
||||||
completion_obj.on_clear_completion_selection)
|
completion_obj.on_clear_completion_selection)
|
||||||
cmd.hide_completion.connect(completion_obj.hide)
|
cmd.hide_completion.connect(completion_obj.hide)
|
||||||
cmd.update_completion.connect(completer.on_update_completion)
|
|
||||||
completer.change_completed_part.connect(cmd.on_change_completed_part)
|
|
||||||
|
|
||||||
# downloads
|
# downloads
|
||||||
tabs.start_download.connect(download_manager.fetch)
|
tabs.start_download.connect(download_manager.fetch)
|
||||||
|
@ -23,7 +23,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl
|
|||||||
from PyQt5.QtWidgets import QSizePolicy
|
from PyQt5.QtWidgets import QSizePolicy
|
||||||
|
|
||||||
from qutebrowser.keyinput import modeman, modeparsers
|
from qutebrowser.keyinput import modeman, modeparsers
|
||||||
from qutebrowser.commands import runners, cmdexc, cmdutils
|
from qutebrowser.commands import cmdexc, cmdutils
|
||||||
from qutebrowser.widgets import misc
|
from qutebrowser.widgets import misc
|
||||||
from qutebrowser.models import cmdhistory
|
from qutebrowser.models import cmdhistory
|
||||||
from qutebrowser.utils import usertypes, log, objreg
|
from qutebrowser.utils import usertypes, log, objreg
|
||||||
@ -34,7 +34,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
"""The commandline part of the statusbar.
|
"""The commandline part of the statusbar.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_cursor_part: The part the cursor is currently over.
|
|
||||||
_win_id: The window ID this widget is associated with.
|
_win_id: The window ID this widget is associated with.
|
||||||
|
|
||||||
Signals:
|
Signals:
|
||||||
@ -48,10 +47,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
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 0: The prefix used.
|
|
||||||
arg 1: A list of strings (commandline separated into
|
|
||||||
parts)
|
|
||||||
arg 2: 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.
|
||||||
"""
|
"""
|
||||||
@ -61,7 +56,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
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, list, int)
|
update_completion = pyqtSignal()
|
||||||
show_cmd = pyqtSignal()
|
show_cmd = pyqtSignal()
|
||||||
hide_cmd = pyqtSignal()
|
hide_cmd = pyqtSignal()
|
||||||
|
|
||||||
@ -69,13 +64,9 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
misc.CommandLineEdit.__init__(self, parent)
|
misc.CommandLineEdit.__init__(self, parent)
|
||||||
misc.MinimalLineEditMixin.__init__(self)
|
misc.MinimalLineEditMixin.__init__(self)
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
self._cursor_part = 0
|
|
||||||
self.history.history = objreg.get('command-history').data
|
self.history.history = objreg.get('command-history').data
|
||||||
self._empty_item_idx = None
|
|
||||||
self.textEdited.connect(self.on_text_edited)
|
|
||||||
self.cursorPositionChanged.connect(self._update_cursor_part)
|
|
||||||
self.cursorPositionChanged.connect(self.on_cursor_position_changed)
|
|
||||||
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
|
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
|
||||||
|
self.cursorPositionChanged.connect(self.update_completion)
|
||||||
|
|
||||||
def prefix(self):
|
def prefix(self):
|
||||||
"""Get the currently entered command prefix."""
|
"""Get the currently entered command prefix."""
|
||||||
@ -87,79 +78,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def split(self, keep=False):
|
|
||||||
"""Get the text split up in parts.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
keep: Whether to keep special chars and whitespace.
|
|
||||||
"""
|
|
||||||
text = self.text()[len(self.prefix()):]
|
|
||||||
if not text:
|
|
||||||
# When only ":" is entered, we already have one imaginary part,
|
|
||||||
# which just is empty at the moment.
|
|
||||||
return ['']
|
|
||||||
if not text.strip():
|
|
||||||
# Text is only whitespace so we treat this as a single element with
|
|
||||||
# the whitespace.
|
|
||||||
return [text]
|
|
||||||
runner = runners.CommandRunner(self._win_id)
|
|
||||||
parts = runner.parse(text, fallback=True, alias_no_args=False,
|
|
||||||
keep=keep)
|
|
||||||
if self._empty_item_idx is not None:
|
|
||||||
log.completion.debug("Empty element queued at {}, "
|
|
||||||
"inserting.".format(self._empty_item_idx))
|
|
||||||
parts.insert(self._empty_item_idx, '')
|
|
||||||
#log.completion.debug("Splitting '{}' -> {}".format(text, parts))
|
|
||||||
return parts
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def _update_cursor_part(self):
|
|
||||||
"""Get the part index of the commandline where the cursor is over."""
|
|
||||||
cursor_pos = self.cursorPosition()
|
|
||||||
snippet = slice(cursor_pos - 1, cursor_pos + 1)
|
|
||||||
if self.text()[snippet] == ' ':
|
|
||||||
spaces = True
|
|
||||||
else:
|
|
||||||
spaces = False
|
|
||||||
cursor_pos -= len(self.prefix())
|
|
||||||
parts = self.split(keep=True)
|
|
||||||
log.completion.vdebug(
|
|
||||||
"text: {}, parts: {}, cursor_pos after removing prefix '{}': "
|
|
||||||
"{}".format(self.text(), parts, self.prefix(), cursor_pos))
|
|
||||||
for i, part in enumerate(parts):
|
|
||||||
log.completion.vdebug("Checking part {}: {}".format(i, parts[i]))
|
|
||||||
if cursor_pos <= len(part):
|
|
||||||
# foo| bar
|
|
||||||
self._cursor_part = i
|
|
||||||
if spaces:
|
|
||||||
self._empty_item_idx = i
|
|
||||||
else:
|
|
||||||
self._empty_item_idx = None
|
|
||||||
log.completion.vdebug("cursor_pos {} <= len(part) {}, "
|
|
||||||
"setting cursor_part {}, empty_item_idx "
|
|
||||||
"{}".format(cursor_pos, len(part), i,
|
|
||||||
self._empty_item_idx))
|
|
||||||
break
|
|
||||||
cursor_pos -= len(part)
|
|
||||||
log.completion.vdebug(
|
|
||||||
"Removing len({!r}) -> {} from cursor_pos -> {}".format(
|
|
||||||
part, len(part), cursor_pos))
|
|
||||||
else:
|
|
||||||
self._cursor_part = i
|
|
||||||
if spaces:
|
|
||||||
self._empty_item_idx = i
|
|
||||||
else:
|
|
||||||
self._empty_item_idx = None
|
|
||||||
log.completion.debug("cursor_part {}, spaces {}".format(
|
|
||||||
self._cursor_part, spaces))
|
|
||||||
return
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def on_cursor_position_changed(self):
|
|
||||||
"""Update completion when the cursor position changed."""
|
|
||||||
self.update_completion.emit(self.prefix(), self.split(),
|
|
||||||
self._cursor_part)
|
|
||||||
|
|
||||||
@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.
|
||||||
@ -172,8 +90,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
if old_text != text and len(old_text) == len(text):
|
if old_text != text and len(old_text) == len(text):
|
||||||
# We want the completion to pop out here, but the cursor position
|
# We want the completion to pop out here, but the cursor position
|
||||||
# won't change, so we make sure we emit update_completion.
|
# won't change, so we make sure we emit update_completion.
|
||||||
self.update_completion.emit(self.prefix(), self.split(),
|
self.update_completion.emit()
|
||||||
self._cursor_part)
|
|
||||||
log.modes.debug("Setting command text, focusing {!r}".format(self))
|
log.modes.debug("Setting command text, focusing {!r}".format(self))
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
self.show_cmd.emit()
|
self.show_cmd.emit()
|
||||||
@ -207,41 +124,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
"Invalid command text '{}'.".format(text))
|
"Invalid command text '{}'.".format(text))
|
||||||
self.set_cmd_text(text)
|
self.set_cmd_text(text)
|
||||||
|
|
||||||
@pyqtSlot(str, bool)
|
|
||||||
def on_change_completed_part(self, newtext, immediate):
|
|
||||||
"""Change the part we're currently completing in the commandline.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text: The text to set (string).
|
|
||||||
immediate: True if the text should be completed immediately
|
|
||||||
including a trailing space and we shouldn't continue
|
|
||||||
completing the current item.
|
|
||||||
"""
|
|
||||||
parts = self.split()
|
|
||||||
log.completion.debug("changing part {} to '{}'".format(
|
|
||||||
self._cursor_part, newtext))
|
|
||||||
try:
|
|
||||||
parts[self._cursor_part] = newtext
|
|
||||||
except IndexError:
|
|
||||||
parts.append(newtext)
|
|
||||||
# We want to place the cursor directly after the part we just changed.
|
|
||||||
cursor_str = self.prefix() + ' '.join(parts[:self._cursor_part + 1])
|
|
||||||
if immediate:
|
|
||||||
# If we should complete immediately, we want to move the cursor by
|
|
||||||
# one more char, to get to the next field.
|
|
||||||
cursor_str += ' '
|
|
||||||
text = self.prefix() + ' '.join(parts)
|
|
||||||
if immediate and self._cursor_part == len(parts) - 1:
|
|
||||||
# If we should complete immediately and we're completing the last
|
|
||||||
# part in the commandline, we automatically add a space.
|
|
||||||
text += ' '
|
|
||||||
self.setText(text)
|
|
||||||
log.completion.debug("Placing cursor after '{}'".format(cursor_str))
|
|
||||||
log.modes.debug("Completion triggered, focusing {!r}".format(self))
|
|
||||||
self.setCursorPosition(len(cursor_str))
|
|
||||||
self.setFocus()
|
|
||||||
self.show_cmd.emit()
|
|
||||||
|
|
||||||
@cmdutils.register(instance='status-command', hide=True,
|
@cmdutils.register(instance='status-command', hide=True,
|
||||||
modes=[usertypes.KeyMode.command], scope='window')
|
modes=[usertypes.KeyMode.command], scope='window')
|
||||||
def command_history_prev(self):
|
def command_history_prev(self):
|
||||||
@ -285,15 +167,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
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._empty_item_idx = None
|
|
||||||
# We also want to update the cursor part and emit update_completion
|
|
||||||
# here, but that's already done for us by cursorPositionChanged
|
|
||||||
# anyways, so we don't need to do it twice.
|
|
||||||
|
|
||||||
@pyqtSlot(usertypes.KeyMode)
|
@pyqtSlot(usertypes.KeyMode)
|
||||||
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