Don't regenerate completion model needlessly.
If the completion model would stay the same, just keep it and update the filter pattern rather than instantiating a new model each time the pattern changes.
This commit is contained in:
parent
2cd02be7b1
commit
c297f047d2
@ -39,6 +39,7 @@ class Completer(QObject):
|
||||
_last_cursor_pos: The old cursor position so we avoid double completion
|
||||
updates.
|
||||
_last_text: The old command text so we avoid double completion updates.
|
||||
_last_completion_func: The completion function used for the last text.
|
||||
"""
|
||||
|
||||
def __init__(self, cmd, win_id, parent=None):
|
||||
@ -52,6 +53,7 @@ class Completer(QObject):
|
||||
self._timer.timeout.connect(self._update_completion)
|
||||
self._last_cursor_pos = None
|
||||
self._last_text = None
|
||||
self._last_completion_func = None
|
||||
self._cmd.update_completion.connect(self.schedule_completion_update)
|
||||
|
||||
def __repr__(self):
|
||||
@ -63,7 +65,7 @@ class Completer(QObject):
|
||||
return completion.model()
|
||||
|
||||
def _get_new_completion(self, before_cursor, under_cursor):
|
||||
"""Get a new completion.
|
||||
"""Get the completion function based on the current command text.
|
||||
|
||||
Args:
|
||||
before_cursor: The command chunks before the cursor.
|
||||
@ -81,7 +83,7 @@ class Completer(QObject):
|
||||
if not before_cursor:
|
||||
# '|' or 'set|'
|
||||
log.completion.debug('Starting command completion')
|
||||
return miscmodels.command()
|
||||
return miscmodels.command
|
||||
try:
|
||||
cmd = cmdutils.cmd_dict[before_cursor[0]]
|
||||
except KeyError:
|
||||
@ -90,17 +92,11 @@ class Completer(QObject):
|
||||
return None
|
||||
argpos = len(before_cursor) - 1
|
||||
try:
|
||||
completion = cmd.get_pos_arg_info(argpos).completion
|
||||
func = cmd.get_pos_arg_info(argpos).completion
|
||||
except IndexError:
|
||||
log.completion.debug("No completion in position {}".format(argpos))
|
||||
return None
|
||||
if completion is None:
|
||||
return None
|
||||
|
||||
model = completion(*before_cursor[1:])
|
||||
log.completion.debug('Starting {} completion'
|
||||
.format(completion.__name__))
|
||||
return model
|
||||
return func
|
||||
|
||||
def _quote(self, s):
|
||||
"""Quote s if it needs quoting for the commandline.
|
||||
@ -223,9 +219,24 @@ class Completer(QObject):
|
||||
before_cursor, pattern, after_cursor))
|
||||
|
||||
pattern = pattern.strip("'\"")
|
||||
model = self._get_new_completion(before_cursor, pattern)
|
||||
log.completion.debug("Setting pattern to '{}'".format(pattern))
|
||||
completion.set_model(model, pattern)
|
||||
func = self._get_new_completion(before_cursor, pattern)
|
||||
|
||||
if func is None:
|
||||
log.completion.debug('Clearing completion')
|
||||
completion.set_model(None)
|
||||
elif func != self._last_completion_func:
|
||||
self._last_completion_func = func
|
||||
args = (x for x in before_cursor[1:] if not x.startswith('-'))
|
||||
model = func(*args)
|
||||
log.completion.debug('Starting {} completion'
|
||||
.format(func.__name__))
|
||||
completion.set_model(model)
|
||||
completion.set_pattern(pattern)
|
||||
else:
|
||||
log.completion.debug('Setting pattern {}'.format(pattern))
|
||||
completion.set_pattern(pattern)
|
||||
|
||||
self._last_completion_func = None
|
||||
|
||||
def _change_completed_part(self, newtext, before, after, immediate=False):
|
||||
"""Change the part we're currently completing in the commandline.
|
||||
|
@ -261,32 +261,29 @@ class CompletionView(QTreeView):
|
||||
elif config.get('completion', 'show') == 'auto':
|
||||
self.show()
|
||||
|
||||
def set_model(self, model, pattern=None):
|
||||
def set_model(self, model):
|
||||
"""Switch completion to a new model.
|
||||
|
||||
Called from on_update_completion().
|
||||
|
||||
Args:
|
||||
model: The model to use.
|
||||
pattern: The filter pattern to set (what the user entered).
|
||||
"""
|
||||
if model is None:
|
||||
self._active = False
|
||||
self.hide()
|
||||
return
|
||||
|
||||
if self.model() is not None:
|
||||
self.model().deleteLater()
|
||||
self.selectionModel().deleteLater()
|
||||
|
||||
model.setParent(self)
|
||||
old_model = self.model()
|
||||
if model is not old_model:
|
||||
sel_model = self.selectionModel()
|
||||
self.setModel(model)
|
||||
self._column_widths = model.column_widths
|
||||
self._active = True
|
||||
|
||||
self.setModel(model)
|
||||
self._active = True
|
||||
|
||||
if sel_model is not None:
|
||||
sel_model.deleteLater()
|
||||
if old_model is not None:
|
||||
old_model.deleteLater()
|
||||
self.set_pattern('')
|
||||
|
||||
if (config.get('completion', 'show') == 'always' and
|
||||
model.count() > 0):
|
||||
@ -297,12 +294,11 @@ class CompletionView(QTreeView):
|
||||
for i in range(model.rowCount()):
|
||||
self.expand(model.index(i, 0))
|
||||
|
||||
if pattern is not None:
|
||||
model.set_pattern(pattern)
|
||||
|
||||
self._column_widths = model.column_widths
|
||||
def set_pattern(self, pattern):
|
||||
self.model().set_pattern(pattern)
|
||||
self._resize_columns()
|
||||
self._maybe_update_geometry()
|
||||
self.show()
|
||||
|
||||
def _maybe_update_geometry(self):
|
||||
"""Emit the update_geometry signal if the config says so."""
|
||||
|
@ -137,6 +137,7 @@ def bind(_key):
|
||||
_key: the key being bound.
|
||||
"""
|
||||
# TODO: offer a 'Current binding' completion based on the key.
|
||||
print(_key)
|
||||
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
|
||||
cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
|
||||
model.add_category(listcategory.ListCategory("Commands", cmdlist))
|
||||
|
@ -191,15 +191,14 @@ def test_update_completion(txt, kind, pattern, pos_args, status_command_stub,
|
||||
# this test uses | as a placeholder for the current cursor position
|
||||
_set_cmd_prompt(status_command_stub, txt)
|
||||
completer_obj.schedule_completion_update()
|
||||
assert completion_widget_stub.set_model.call_count == 1
|
||||
args = completion_widget_stub.set_model.call_args[0]
|
||||
if kind is None:
|
||||
assert args[0] is None
|
||||
assert completion_widget_stub.set_pattern.call_count == 0
|
||||
else:
|
||||
model = args[0]
|
||||
assert completion_widget_stub.set_model.call_count == 1
|
||||
model = completion_widget_stub.set_model.call_args[0][0]
|
||||
assert model.kind == kind
|
||||
assert model.pos_args == pos_args
|
||||
assert args[1] == pattern
|
||||
completion_widget_stub.set_pattern.assert_called_once_with(pattern)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('before, newtxt, after', [
|
||||
|
@ -84,7 +84,8 @@ def test_set_model(completionview):
|
||||
def test_set_pattern(completionview):
|
||||
model = completionmodel.CompletionModel()
|
||||
model.set_pattern = mock.Mock()
|
||||
completionview.set_model(model, 'foo')
|
||||
completionview.set_model(model)
|
||||
completionview.set_pattern('foo')
|
||||
model.set_pattern.assert_called_with('foo')
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user