diff --git a/qutebrowser/completion/completionwidget.py b/qutebrowser/completion/completionwidget.py index 43ebffa84..bec0e6511 100644 --- a/qutebrowser/completion/completionwidget.py +++ b/qutebrowser/completion/completionwidget.py @@ -377,3 +377,17 @@ class CompletionView(QTreeView): if not index.isValid(): raise cmdexc.CommandError("No item selected!") self.model().delete_cur_item(index) + + @cmdutils.register(instance='completion', hide=True, + modes=[usertypes.KeyMode.command], scope='window') + def completion_item_yank(self, sel=False): + """Yank the current completion item onto the clipboard. + + Args: + sel: True to use the primary selection instead of the clipboard. + """ + index = self.currentIndex() + if not index.isValid(): + raise cmdexc.CommandError("No item selected!") + data = self.model().data(index) + utils.set_clipboard(data, selection=sel) diff --git a/tests/unit/completion/test_completionwidget.py b/tests/unit/completion/test_completionwidget.py index 22c71a2b7..500f9614a 100644 --- a/tests/unit/completion/test_completionwidget.py +++ b/tests/unit/completion/test_completionwidget.py @@ -245,6 +245,23 @@ def test_completion_item_del_no_selection(completionview): func.assert_not_called() +@pytest.mark.parametrize('sel', [True, False]) +def test_completion_item_yank(completionview, mocker, sel): + """Test that completion_item_yank invokes delete_cur_item in the model.""" + m = mocker.patch( + 'qutebrowser.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 test_resize_no_model(completionview, qtbot): """Ensure no crash if resizeEvent is triggered with no model (#2854).""" completionview.resizeEvent(None)