def value(optname, *values, info): """A CompletionModel filled with setting values. Args: optname: The name of the config option this model shows. values: The values already provided on the command line. info: A CompletionInfo instance. """ model = completionmodel.CompletionModel(column_widths=(30, 70, 0)) try: current = info.config.get_str(optname) except configexc.NoOptionError: return None opt = info.config.get_opt(optname) default = opt.typ.to_str(opt.default) cur_def = [] if current not in values: cur_def.append((current, "Current value")) if default not in values: cur_def.append((default, "Default value")) if cur_def: cur_cat = listcategory.ListCategory("Current/Default", cur_def) model.add_category(cur_cat) vals = opt.typ.complete() or [] vals = [x for x in vals if x[0] not in values] if vals: model.add_category(listcategory.ListCategory("Completions", vals)) return model
def test_completion_item_focus_fetch(completionview, qtbot): """Test that on_next_prev_item moves the selection properly. Args: which: the direction in which to move the selection. tree: Each list represents a completion category, with each string being an item under that category. expected: expected argument from on_selection_changed for each successive movement. None implies no signal should be emitted. """ model = completionmodel.CompletionModel() cat = mock.Mock(spec=[ 'layoutChanged', 'layoutAboutToBeChanged', 'canFetchMore', 'fetchMore', 'rowCount', 'index', 'data' ]) cat.canFetchMore = lambda *_: True cat.rowCount = lambda *_: 2 cat.fetchMore = mock.Mock() model.add_category(cat) completionview.set_model(model) # clear the fetchMore call that happens on set_model cat.reset_mock() # not at end, fetchMore shouldn't be called completionview.completion_item_focus('next') assert not cat.fetchMore.called # at end, fetchMore should be called completionview.completion_item_focus('next') assert cat.fetchMore.called
def test_completion_show(show, rows, quick_complete, completionview, config_stub): """Test that the completion widget is shown at appropriate times. Args: show: The completion show config setting. rows: Each entry represents a completion category with only one item. quick_complete: The `completion.quick` config setting. """ config_stub.val.completion.show = show config_stub.val.completion.quick = quick_complete model = completionmodel.CompletionModel() for name in rows: cat = listcategory.ListCategory('', [(name, )]) model.add_category(cat) assert not completionview.isVisible() completionview.set_model(model) assert completionview.isVisible() == (show == 'always' and len(rows) > 0) completionview.completion_item_focus('next') expected = (show != 'never' and len(rows) > 0 and not (quick_complete and len(rows) == 1)) assert completionview.isVisible() == expected completionview.set_model(None) completionview.completion_item_focus('next') assert not completionview.isVisible()
def test_set_pattern(completionview): model = completionmodel.CompletionModel() model.set_pattern = mock.Mock(spec=[]) completionview.set_model(model) completionview.set_pattern('foo') model.set_pattern.assert_called_with('foo') assert not completionview.selectionModel().currentIndex().isValid()
def command(*, info): """A CompletionModel filled with non-hidden commands and descriptions.""" model = completionmodel.CompletionModel(column_widths=(20, 60, 20)) cmdlist = util.get_cmd_completions(info, include_aliases=True, include_hidden=False) model.add_category(listcategory.ListCategory("Commands", cmdlist)) return model
def test_count(counts): model = completionmodel.CompletionModel() for c in counts: cat = mock.Mock( spec=['rowCount', 'layoutChanged', 'layoutAboutToBeChanged']) cat.rowCount = mock.Mock(return_value=c, spec=[]) model.add_category(cat) assert model.count() == sum(counts)
def test_delete_cur_item(): func = mock.Mock(spec=[]) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', 'bar')], delete_func=func) model.add_category(cat) parent = model.index(0, 0) model.delete_cur_item(model.index(0, 0, parent)) func.assert_called_once_with(['foo', 'bar'])
def test_set_model(completionview): """Ensure set_model actually sets the model and expands all categories.""" model = completionmodel.CompletionModel() for _i in range(3): model.add_category(listcategory.ListCategory('', [('foo', )])) completionview.set_model(model) assert completionview.model() is model for i in range(3): assert completionview.isExpanded(model.index(i, 0))
def test_delete_cur_item_no_cat(): """Test completion_item_del with no selected category.""" callback = mock.Mock(spec=[]) model = completionmodel.CompletionModel() model.rowsAboutToBeRemoved.connect(callback) model.rowsRemoved.connect(callback) with pytest.raises(qtutils.QtValueError): model.delete_cur_item(QModelIndex()) callback.assert_not_called()
def customized_option(*, info): """A CompletionModel filled with set settings and their descriptions.""" model = completionmodel.CompletionModel(column_widths=(20, 70, 10)) options = ((values.opt.name, values.opt.description, info.config.get_str(values.opt.name)) for values in info.config if values) model.add_category(listcategory.ListCategory("Customized options", options)) return model
def test_completion_item_del(completionview): """Test that completion_item_del invokes delete_cur_item in the model.""" func = mock.Mock(spec=[]) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', 'bar')], delete_func=func) model.add_category(cat) completionview.set_model(model) completionview.completion_item_focus('next') completionview.completion_item_del() func.assert_called_once_with(['foo', 'bar'])
def test_completion_item_del_no_selection(completionview): """Test that completion_item_del with an invalid index.""" func = mock.Mock(spec=[]) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', )], delete_func=func) model.add_category(cat) completionview.set_model(model) with pytest.raises(cmdutils.CommandError, match='No item selected!'): completionview.completion_item_del() func.assert_not_called()
def session(*, info=None): # pylint: disable=unused-argument """A CompletionModel filled with session names.""" model = completionmodel.CompletionModel() try: manager = objreg.get('session-manager') sessions = ((name, ) for name in manager.list_sessions() if not name.startswith('_')) model.add_category(listcategory.ListCategory("Sessions", sessions)) except OSError: log.completion.exception("Failed to list sessions!") return model
def test_delete_cur_item_no_func(): callback = mock.Mock(spec=[]) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', 'bar')], delete_func=None) model.rowsAboutToBeRemoved.connect(callback) model.rowsRemoved.connect(callback) model.add_category(cat) parent = model.index(0, 0) with pytest.raises(cmdutils.CommandError): model.delete_cur_item(model.index(0, 0, parent)) callback.assert_not_called()
def test_set_pattern(pat, qtbot): """Validate the filtering and sorting results of set_pattern.""" model = completionmodel.CompletionModel() cats = [mock.Mock(spec=['set_pattern']) for _ in range(3)] for c in cats: c.set_pattern = mock.Mock(spec=[]) model.add_category(c) with qtbot.waitSignals([model.layoutAboutToBeChanged, model.layoutChanged], order='strict'): model.set_pattern(pat) for c in cats: c.set_pattern.assert_called_with(pat)
def test_completion_item_focus_no_model(which, completionview, qtbot): """Test that selectionChanged is not fired when the model is None. Validates #1812: help completion repeatedly completes """ with qtbot.assertNotEmitted(completionview.selection_changed): completionview.completion_item_focus(which) model = completionmodel.CompletionModel() completionview.set_model(model) completionview.set_model(None) with qtbot.assertNotEmitted(completionview.selection_changed): completionview.completion_item_focus(which)
def test_completion_item_yank(completionview, mocker, sel): """Test that completion_item_yank invokes delete_cur_item in the model.""" m = mocker.patch('glimpsebrowser.completion.completionwidget.utils', autospec=True) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', 'bar')]) model.add_category(cat) completionview.set_model(model) completionview.completion_item_focus('next') completionview.completion_item_yank(sel) m.set_clipboard.assert_called_once_with('foo', sel)
def _option(info, title, predicate): """A CompletionModel that is generated for several option sets. Args: info: The config info that can be passed through. title: The title of the options. predicate: The function for filtering out the options. Takes a single argument. """ model = completionmodel.CompletionModel(column_widths=(20, 70, 10)) options = ((opt.name, opt.description, info.config.get_str(opt.name)) for opt in configdata.DATA.values() if predicate(opt)) model.add_category(listcategory.ListCategory(title, options)) return model
def helptopic(*, info): """A CompletionModel filled with help topics.""" model = completionmodel.CompletionModel() cmdlist = util.get_cmd_completions(info, include_aliases=False, include_hidden=True, prefix=':') settings = ((opt.name, opt.description) for opt in configdata.DATA.values()) model.add_category(listcategory.ListCategory("Commands", cmdlist)) model.add_category(listcategory.ListCategory("Settings", settings)) return model
def url(*, info): """A model which combines various URLs. This combines: - bookmarks - quickmarks - search engines - web history URLs Used for the `open` command. """ model = completionmodel.CompletionModel(column_widths=(40, 50, 10)) # pylint: disable=bad-config-option quickmarks = [(url, name) for (name, url) in objreg.get('quickmark-manager').marks.items()] bookmarks = objreg.get('bookmark-manager').marks.items() searchengines = [(k, v) for k, v in sorted(config.val.url.searchengines.items()) if k != 'DEFAULT'] # pylint: enable=bad-config-option categories = config.val.completion.open_categories models = {} if searchengines and 'searchengines' in categories: models['searchengines'] = listcategory.ListCategory('Search engines', searchengines, sort=False) if quickmarks and 'quickmarks' in categories: models['quickmarks'] = listcategory.ListCategory( 'Quickmarks', quickmarks, delete_func=_delete_quickmark, sort=False) if bookmarks and 'bookmarks' in categories: models['bookmarks'] = listcategory.ListCategory( 'Bookmarks', bookmarks, delete_func=_delete_bookmark, sort=False) history_disabled = info.config.get('completion.web_history.max_items') == 0 if not history_disabled and 'history' in categories: hist_cat = histcategory.HistoryCategory(delete_func=_delete_history) models['history'] = hist_cat for category in categories: if category in models: model.add_category(models[category]) return model
def test_completion_item_yank_selected(completionview, status_command_stub, mocker, sel): """Test that completion_item_yank yanks selected text.""" m = mocker.patch('glimpsebrowser.completion.completionwidget.utils', autospec=True) model = completionmodel.CompletionModel() cat = listcategory.ListCategory('', [('foo', 'bar')]) model.add_category(cat) completionview.set_model(model) completionview.completion_item_focus('next') status_command_stub.selectedText = mock.Mock(return_value='something') completionview.completion_item_yank(sel) m.set_clipboard.assert_called_once_with('something', sel)
def bookmark(*, info=None): # pylint: disable=unused-argument """A CompletionModel filled with all bookmarks.""" def delete(data: typing.Sequence[int]) -> None: """Delete a bookmark from the completion menu.""" urlstr = data[0] log.completion.debug('Deleting bookmark {}'.format(urlstr)) bookmark_manager = objreg.get('bookmark-manager') bookmark_manager.delete(urlstr) model = completionmodel.CompletionModel(column_widths=(30, 70, 0)) marks = objreg.get('bookmark-manager').marks.items() model.add_category( listcategory.ListCategory('Bookmarks', marks, delete_func=delete, sort=False)) return model
def bind(key, *, info): """A CompletionModel filled with all bindable commands and descriptions. Args: key: the key being bound. """ model = completionmodel.CompletionModel(column_widths=(20, 60, 20)) data = _bind_current_default(key, info) if data: model.add_category(listcategory.ListCategory("Current/Default", data)) cmdlist = util.get_cmd_completions(info, include_hidden=True, include_aliases=True) model.add_category(listcategory.ListCategory("Commands", cmdlist)) return model
def window(*, info): """A model to complete on all open windows.""" model = completionmodel.CompletionModel(column_widths=(6, 30, 64)) windows = [] for win_id in objreg.window_registry: if win_id == info.win_id: continue tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tab_titles = (tab.title() for tab in tabbed_browser.widgets()) windows.append( ("{}".format(win_id), objreg.window_registry[win_id].windowTitle(), ", ".join(tab_titles))) model.add_category(listcategory.ListCategory("Windows", windows)) return model
def test_first_last_item(counts): """Test that first() and last() index to the first and last items.""" model = completionmodel.CompletionModel() for c in counts: cat = mock.Mock(spec=['layoutChanged', 'layoutAboutToBeChanged']) cat.rowCount = mock.Mock(return_value=c, spec=[]) model.add_category(cat) data = [i for i, row_count in enumerate(counts) if row_count > 0] if not data: # with no items, first and last should be an invalid index assert not model.first_item().isValid() assert not model.last_item().isValid() else: first = data[0] last = data[-1] # first item of the first data category assert model.first_item().row() == 0 assert model.first_item().parent().row() == first # last item of the last data category assert model.last_item().row() == counts[last] - 1 assert model.last_item().parent().row() == last
def _buffer(skip_win_id=None): """Helper to get the completion model for buffer/other_buffer. Args: skip_win_id: The id of the window to skip, or None to include all. """ def delete_buffer(data): """Close the selected tab.""" win_id, tab_index = data[0].split('/') tabbed_browser = objreg.get('tabbed-browser', scope='window', window=int(win_id)) tabbed_browser.on_tab_close_requested(int(tab_index) - 1) model = completionmodel.CompletionModel(column_widths=(6, 40, 54)) for win_id in objreg.window_registry: if skip_win_id is not None and win_id == skip_win_id: continue tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) if tabbed_browser.shutting_down: continue tabs = [] for idx in range(tabbed_browser.widget.count()): tab = tabbed_browser.widget.widget(idx) tabs.append(("{}/{}".format(win_id, idx + 1), tab.url().toDisplayString(), tabbed_browser.widget.page_title(idx))) cat = listcategory.ListCategory(str(win_id), tabs, delete_func=delete_buffer, sort=False) model.add_category(cat) return model
def test_completion_item_focus(which, tree, expected, completionview, qtbot): """Test that on_next_prev_item moves the selection properly. Args: which: the direction in which to move the selection. tree: Each list represents a completion category, with each string being an item under that category. expected: expected argument from on_selection_changed for each successive movement. None implies no signal should be emitted. """ model = completionmodel.CompletionModel() for catdata in tree: cat = listcategory.ListCategory('', ((x, ) for x in catdata)) model.add_category(cat) completionview.set_model(model) for entry in expected: if entry is None: with qtbot.assertNotEmitted(completionview.selection_changed): completionview.completion_item_focus(which) else: with qtbot.waitSignal(completionview.selection_changed) as sig: completionview.completion_item_focus(which) assert sig.args == [entry]