From 4d7e39470e62590031c093152e9cdd9691b1c879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Thu, 21 Jan 2016 22:02:08 +0100 Subject: [PATCH 01/24] Added paste-primary command The Shift+Ins key should arguably insert primary selection, not the clipboard selection as every Qt program does. This commit makes it possible via the hidden paste-primary command (enabled by default). Unfortunately QtWebKit does not provide any straightforward way to insert text at cursor position into editable fields, so we work around this by executing a JavaScript snippet - inspired by this SO answer: http://stackoverflow.com/a/11077016 --- qutebrowser/browser/commands.py | 33 ++++++++++++++++++++++++++++++++ qutebrowser/config/configdata.py | 4 +++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index e1d293781..aac584621 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1307,6 +1307,39 @@ class CommandDispatcher: except webelem.IsNullError: raise cmdexc.CommandError("Element vanished while editing!") + @cmdutils.register(instance='command-dispatcher', + modes=[KeyMode.insert], hide=True, scope='window') + def paste_primary(self): + """Paste the primary selection at cursor position into the curently + selected form field. + """ + frame = self._current_widget().page().currentFrame() + try: + elem = webelem.focus_elem(frame) + except webelem.IsNullError: + raise cmdexc.CommandError("No element focused!") + if not elem.is_editable(strict=True): + raise cmdexc.CommandError("Focused element is not editable!") + + clipboard = QApplication.clipboard() + if clipboard.supportsSelection(): + sel = clipboard.text(QClipboard.Selection) + log.misc.debug("Pasting selection: '{}'".format(sel)) + elem.evaluateJavaScript(""" + var sel = '%s'; + if (this.selectionStart || this.selectionStart == '0') { + var startPos = this.selectionStart; + var endPos = this.selectionEnd; + this.value = this.value.substring(0, startPos) + + sel + + this.value.substring(endPos, this.value.length); + this.selectionStart = startPos + sel.length; + this.selectionEnd = startPos + sel.length; + } else { + this.value += sel; + } + """ % sel) + def _clear_search(self, view, text): """Clear search string/highlights for the given view. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index a9fbb2669..d94ad572e 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1324,7 +1324,8 @@ KEY_SECTION_DESC = { "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" "Useful hidden commands to map in this section:\n\n" - " * `open-editor`: Open a texteditor with the focused field."), + " * `open-editor`: Open a texteditor with the focused field.\n" + " * `paste-primary`: Paste primary selection at cursor position."), 'hint': ( "Keybindings for hint mode.\n" "Since normal keypresses are passed through, only special keys are " @@ -1495,6 +1496,7 @@ KEY_DATA = collections.OrderedDict([ ('insert', collections.OrderedDict([ ('open-editor', ['']), + ('paste-primary', ['']), ])), ('hint', collections.OrderedDict([ From 35e16a8e6ea7ae4aa33a44ccbe4c7ad29f205899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Fri, 22 Jan 2016 18:18:17 +0100 Subject: [PATCH 02/24] paste-primary: fix undo/redo not working It seems that unlike Gecko, WebKit does not support undo/redo operations when the textarea's `value` attribute is changed directly. Fortunately there is a WebKit-specific workaround using textInput event. References: * http://stackoverflow.com/a/7554295 * http://help.dottoro.com/ljuecqgv.php --- qutebrowser/browser/commands.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index aac584621..b254efbcf 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1324,21 +1324,14 @@ class CommandDispatcher: clipboard = QApplication.clipboard() if clipboard.supportsSelection(): sel = clipboard.text(QClipboard.Selection) - log.misc.debug("Pasting selection: '{}'".format(sel)) + log.misc.debug("Pasting primary selection into element {} " + "(selection is '{}')".format(elem.debug_text(), sel)) elem.evaluateJavaScript(""" - var sel = '%s'; - if (this.selectionStart || this.selectionStart == '0') { - var startPos = this.selectionStart; - var endPos = this.selectionEnd; - this.value = this.value.substring(0, startPos) - + sel - + this.value.substring(endPos, this.value.length); - this.selectionStart = startPos + sel.length; - this.selectionEnd = startPos + sel.length; - } else { - this.value += sel; - } - """ % sel) + var sel = '{}'; + var event = document.createEvent('TextEvent'); + event.initTextEvent('textInput', true, true, null, sel); + this.dispatchEvent(event); + """.format(sel)) def _clear_search(self, view, text): """Clear search string/highlights for the given view. From 4d9ea067687cf2b7b4b3d738757a1b4aed43d5cb Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 Jan 2016 22:15:31 +0100 Subject: [PATCH 03/24] tests: Make test IDs predictable. This means we could use xdist in the future. --- tests/unit/browser/test_webelem.py | 4 +-- tests/unit/config/test_config.py | 2 +- tests/unit/config/test_configtypes.py | 38 ++++++++++++------------- tests/unit/misc/test_crashdialog.py | 2 +- tests/unit/misc/test_split.py | 7 +++-- tests/unit/utils/overflow_test_cases.py | 12 ++++++-- tests/unit/utils/test_qtutils.py | 6 ++-- tests/unit/utils/test_utils.py | 3 +- 8 files changed, 42 insertions(+), 32 deletions(-) diff --git a/tests/unit/browser/test_webelem.py b/tests/unit/browser/test_webelem.py index 654bd3a7d..f36b16694 100644 --- a/tests/unit/browser/test_webelem.py +++ b/tests/unit/browser/test_webelem.py @@ -599,7 +599,7 @@ class TestJavascriptEscape: # http://qutebrowser.org:8010/builders/debian-jessie/builds/765/steps/unittests/ # Should that be ignored? - @pytest.mark.parametrize('before, after', TESTS.items(), ids=repr) + @pytest.mark.parametrize('before, after', sorted(TESTS.items()), ids=repr) def test_fake_escape(self, before, after): """Test javascript escaping with some expected outcomes.""" assert webelem.javascript_escape(before) == after @@ -645,7 +645,7 @@ class TestJavascriptEscape: result = webframe.evaluateJavaScript('"{}";'.format(escaped)) assert result == text - @pytest.mark.parametrize('text', TESTS, ids=repr) + @pytest.mark.parametrize('text', sorted(TESTS), ids=repr) def test_real_escape(self, webframe, qtbot, text): """Test javascript escaping with a real QWebPage.""" self._test_escape(text, qtbot, webframe) diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py index cb06364fd..a1d941137 100644 --- a/tests/unit/config/test_config.py +++ b/tests/unit/config/test_config.py @@ -189,7 +189,7 @@ class TestConfigParser: assert new_sect in configdata.DATA @pytest.mark.parametrize('old_tuple, new_option', - config.ConfigManager.RENAMED_OPTIONS.items()) + sorted(config.ConfigManager.RENAMED_OPTIONS.items())) def test_renamed_options(self, old_tuple, new_option): """Make sure renamed options exist under the new name.""" section, old_option = old_tuple diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py index 34f4329fc..cacc898ee 100644 --- a/tests/unit/config/test_configtypes.py +++ b/tests/unit/config/test_configtypes.py @@ -254,7 +254,7 @@ class TestMappingType: def klass(self): return MappingSubclass - @pytest.mark.parametrize('val', TESTS.keys()) + @pytest.mark.parametrize('val', sorted(TESTS.keys())) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -263,7 +263,7 @@ class TestMappingType: with pytest.raises(configexc.ValidationError): klass().validate(val) - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected @@ -488,11 +488,11 @@ class TestBool: def klass(self): return configtypes.Bool - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -518,11 +518,11 @@ class TestBoolAsk: def klass(self): return configtypes.BoolAsk - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -871,7 +871,7 @@ class TestColorSystem: def klass(self): return configtypes.ColorSystem - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -880,7 +880,7 @@ class TestColorSystem: with pytest.raises(configexc.ValidationError): klass().validate(val) - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected @@ -1048,7 +1048,7 @@ class TestFont: def qtfont_class(self): return configtypes.QtFont - @pytest.mark.parametrize('val', list(TESTS) + ['']) + @pytest.mark.parametrize('val', sorted(list(TESTS)) + ['']) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -1077,11 +1077,11 @@ class TestFont: with pytest.raises(configexc.ValidationError): klass().validate('') - @pytest.mark.parametrize('string', TESTS) + @pytest.mark.parametrize('string', sorted(TESTS)) def test_transform_font(self, font_class, string): assert font_class().transform(string) == string - @pytest.mark.parametrize('string, desc', TESTS.items()) + @pytest.mark.parametrize('string, desc', sorted(TESTS.items())) def test_transform_qtfont(self, qtfont_class, string, desc): assert Font(qtfont_class().transform(string)) == Font.fromdesc(desc) @@ -1829,7 +1829,7 @@ class TestAutoSearch: def klass(self): return configtypes.AutoSearch - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -1838,7 +1838,7 @@ class TestAutoSearch: with pytest.raises(configexc.ValidationError): klass().validate(val) - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected @@ -1859,7 +1859,7 @@ class TestIgnoreCase: def klass(self): return configtypes.IgnoreCase - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -1868,7 +1868,7 @@ class TestIgnoreCase: with pytest.raises(configexc.ValidationError): klass().validate(val) - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected @@ -1910,7 +1910,7 @@ class TestUrlList: def klass(self): return configtypes.UrlList - @pytest.mark.parametrize('val', TESTS) + @pytest.mark.parametrize('val', sorted(TESTS)) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -1928,7 +1928,7 @@ class TestUrlList: with pytest.raises(configexc.ValidationError): klass().validate('foo,,bar') - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform_single(self, klass, val, expected): assert klass().transform(val) == expected @@ -1968,7 +1968,7 @@ class TestConfirmQuit: def klass(self): return configtypes.ConfirmQuit - @pytest.mark.parametrize('val', TESTS.keys()) + @pytest.mark.parametrize('val', sorted(TESTS.keys())) def test_validate_valid(self, klass, val): klass(none_ok=True).validate(val) @@ -1985,7 +1985,7 @@ class TestConfirmQuit: with pytest.raises(configexc.ValidationError): klass().validate(val) - @pytest.mark.parametrize('val, expected', TESTS.items()) + @pytest.mark.parametrize('val, expected', sorted(TESTS.items())) def test_transform(self, klass, val, expected): assert klass().transform(val) == expected diff --git a/tests/unit/misc/test_crashdialog.py b/tests/unit/misc/test_crashdialog.py index e44bf3559..432bb721e 100644 --- a/tests/unit/misc/test_crashdialog.py +++ b/tests/unit/misc/test_crashdialog.py @@ -94,7 +94,7 @@ class TestParseFatalStacktrace: "QT_IM_MODULE = fcitx" ), ({'LANGUAGE': 'foo', 'LANG': 'en_US.UTF-8'}, "LANG = en_US.UTF-8"), -], ids=repr) +], ids=lambda e: e[1]) def test_get_environment_vars(monkeypatch, env, expected): """Test for crashdialog._get_environment_vars.""" for key in os.environ.copy(): diff --git a/tests/unit/misc/test_split.py b/tests/unit/misc/test_split.py index 265d62079..272b281ea 100644 --- a/tests/unit/misc/test_split.py +++ b/tests/unit/misc/test_split.py @@ -126,7 +126,8 @@ class TestSplit: """Test split.""" - @pytest.fixture(params=_parse_split_test_data_str(), ids=lambda e: e.input) + @pytest.fixture(params=list(_parse_split_test_data_str()), + ids=lambda e: e.input) def split_test_case(self, request): """Fixture to automatically parametrize all depending tests. @@ -163,7 +164,7 @@ class TestSimpleSplit: 'foo\nbar': ['foo', '\nbar'], } - @pytest.mark.parametrize('test', TESTS, ids=repr) + @pytest.mark.parametrize('test', sorted(TESTS), ids=repr) def test_str_split(self, test): """Test if the behavior matches str.split.""" assert split.simple_split(test) == test.rstrip().split() @@ -177,7 +178,7 @@ class TestSimpleSplit: expected = s.rstrip().split(maxsplit=maxsplit) assert actual == expected - @pytest.mark.parametrize('test, expected', TESTS.items(), ids=repr) + @pytest.mark.parametrize('test, expected', sorted(TESTS.items()), ids=repr) def test_split_keep(self, test, expected): """Test splitting with keep=True.""" assert split.simple_split(test, keep=True) == expected diff --git a/tests/unit/utils/overflow_test_cases.py b/tests/unit/utils/overflow_test_cases.py index e209e1827..ff1d73f03 100644 --- a/tests/unit/utils/overflow_test_cases.py +++ b/tests/unit/utils/overflow_test_cases.py @@ -49,12 +49,20 @@ BAD_VALUES = { } +def good_values(): + return list(iter_good_values()) + + +def bad_values(): + return list(iter_bad_values()) + + def iter_good_values(): """Yield "good" (C data type, value) tuples. Those should pass overflow checking. """ - for ctype, values in GOOD_VALUES.items(): + for ctype, values in sorted(GOOD_VALUES.items()): for value in values: yield ctype, value @@ -65,6 +73,6 @@ def iter_bad_values(): These should not pass overflow checking. The third value is the value they should be replaced with if overflow checking should not be fatal. """ - for ctype, values in BAD_VALUES.items(): + for ctype, values in sorted(BAD_VALUES.items()): for value, repl in values: yield ctype, value, repl diff --git a/tests/unit/utils/test_qtutils.py b/tests/unit/utils/test_qtutils.py index 18c15d04a..a429784d0 100644 --- a/tests/unit/utils/test_qtutils.py +++ b/tests/unit/utils/test_qtutils.py @@ -69,21 +69,21 @@ class TestCheckOverflow: """Test check_overflow.""" @pytest.mark.parametrize('ctype, val', - overflow_test_cases.iter_good_values()) + overflow_test_cases.good_values()) def test_good_values(self, ctype, val): """Test values which are inside bounds.""" qtutils.check_overflow(val, ctype) @pytest.mark.parametrize('ctype, val', [(ctype, val) for (ctype, val, _) in - overflow_test_cases.iter_bad_values()]) + overflow_test_cases.bad_values()]) def test_bad_values_fatal(self, ctype, val): """Test values which are outside bounds with fatal=True.""" with pytest.raises(OverflowError): qtutils.check_overflow(val, ctype) @pytest.mark.parametrize('ctype, val, repl', - overflow_test_cases.iter_bad_values()) + overflow_test_cases.bad_values()) def test_bad_values_nonfatal(self, ctype, val, repl): """Test values which are outside bounds with fatal=False.""" newval = qtutils.check_overflow(val, ctype, fatal=False) diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py index da40a43d7..26b3c0920 100644 --- a/tests/unit/utils/test_utils.py +++ b/tests/unit/utils/test_utils.py @@ -805,7 +805,8 @@ QUALNAME_OBJ = QualnameObj() (qutebrowser, 'qutebrowser'), # module (qutebrowser.utils, 'qutebrowser.utils'), # submodule (utils, 'qutebrowser.utils.utils'), # submodule (from-import) -]) +], ids=['instance', 'class', 'unbound-method', 'bound-method', 'function', + 'partial', 'module', 'submodule', 'from-import']) def test_qualname(obj, expected): assert utils.qualname(obj) == expected From ea1627c1e69c4a0485f6f062fcad3d71b10923e1 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 Jan 2016 19:47:31 +0100 Subject: [PATCH 04/24] Cancel permission prompt when tab is closed. Fixes #1250. --- CHANGELOG.asciidoc | 2 ++ qutebrowser/browser/webpage.py | 1 + tests/integration/features/prompts.feature | 9 +++++++++ 3 files changed, 12 insertions(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 165823b99..622e255f9 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -36,6 +36,8 @@ Fixed - Fixed starting with -c "". - Fixed crash when a tab is closed twice via javascript (e.g. Dropbox authentication dialogs) +- Fixed crash when a notification/geolocation prompt is answered after closing + the tab it belongs to. v0.5.1 ------ diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 49a77cc8c..2946f4f12 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -372,6 +372,7 @@ class BrowserPage(QWebPage): q.answered_no.connect(no_action) q.cancelled.connect(no_action) + self.shutting_down.connect(q.abort) q.completed.connect(q.deleteLater) self.featurePermissionRequestCanceled.connect(functools.partial( diff --git a/tests/integration/features/prompts.feature b/tests/integration/features/prompts.feature index d3f77f6da..f00c1184d 100644 --- a/tests/integration/features/prompts.feature +++ b/tests/integration/features/prompts.feature @@ -178,6 +178,15 @@ Feature: Prompts And I run :leave-mode Then the javascript message "notification permission aborted" should be logged + Scenario: answering notification after closing tab + When I set content -> notifications to ask + And I open data/prompt/notifications.html in a new tab + And I click the button + And I wait for a prompt + And I run :tab-close + And I wait for "Leaving mode KeyMode.yesno (reason: aborted)" in the log + Then no crash should happen + # Page authentication Scenario: Successful webpage authentification From 85adf7593dc553806e9de45c00e4a4381ac12ecb Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 Jan 2016 22:37:46 +0100 Subject: [PATCH 05/24] Fix crash when downloading URL without path infos. Fixes #1243. --- CHANGELOG.asciidoc | 2 ++ qutebrowser/browser/downloads.py | 3 +++ tests/integration/data/downloads/issue1243.html | 10 ++++++++++ tests/integration/features/downloads.feature | 10 ++++++++++ 4 files changed, 25 insertions(+) create mode 100644 tests/integration/data/downloads/issue1243.html diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 622e255f9..a706d92dd 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -38,6 +38,8 @@ Fixed authentication dialogs) - Fixed crash when a notification/geolocation prompt is answered after closing the tab it belongs to. +- Fixed crash when downloading a file without any path information (e.g a + magnet link). v0.5.1 ------ diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 448ab120e..8c977fb34 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -774,7 +774,10 @@ class DownloadManager(QAbstractListModel): # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) + suggested_fn = urlutils.filename_from_url(request.url()) + if suggested_fn is None: + suggested_fn = 'qutebrowser-download' # We won't need a question if a filename or fileobj is already given if fileobj is None and filename is None: diff --git a/tests/integration/data/downloads/issue1243.html b/tests/integration/data/downloads/issue1243.html new file mode 100644 index 000000000..d8acd22d3 --- /dev/null +++ b/tests/integration/data/downloads/issue1243.html @@ -0,0 +1,10 @@ + + + + + Crash when trying to get filename from custom URL + + + download + + diff --git a/tests/integration/features/downloads.feature b/tests/integration/features/downloads.feature index 8ed43f8e0..5881767f6 100644 --- a/tests/integration/features/downloads.feature +++ b/tests/integration/features/downloads.feature @@ -24,6 +24,16 @@ Feature: Downloading things from a website. And I wait for the error "Download error: * - server replied: NOT FOUND" Then no crash should happen + Scenario: Downloading a link without path information (issue 1243) + When I set completion -> download-path-suggestion to filename + And I set storage -> prompt-download-directory to true + And I open data/downloads/issue1243.html + And I run :hint links download + And I run :follow-hint a + And I wait for "Asking question text='Save file to:'>, *" in the log + And I run :leave-mode + Then no crash should happen + Scenario: Retrying a failed download When I run :download http://localhost:(port)/does-not-exist And I wait for the error "Download error: * - server replied: NOT FOUND" From d74fb7ed8872aaad4768e40da8175870cf34d580 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 Jan 2016 22:47:20 +0100 Subject: [PATCH 06/24] www: Fix link from FAQ to stacktrace page. See #1268. --- FAQ.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FAQ.asciidoc b/FAQ.asciidoc index 29f4cf5e4..081d4fabc 100644 --- a/FAQ.asciidoc +++ b/FAQ.asciidoc @@ -143,5 +143,5 @@ My issue is not listed.:: https://github.com/The-Compiler/qutebrowser/issues[the issue tracker] or using the `:report` command. If you are reporting a segfault, make sure you read the - https://github.com/The-Compiler/qutebrowser/blob/master/doc/stacktrace.asciidoc[guide] - on how to report them with all needed information. + link:doc/stacktrace.asciidoc[guide] on how to report them with all needed + information. From 959e96f05a3558a731026b8f569f5f1c31823f90 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 Jan 2016 06:41:00 +0100 Subject: [PATCH 07/24] tox: Update ebb-lint to 0.4.4 - Read from stdin - Strip trailing whitespace and \ before tokenizing. - EOF bug? --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 48ba91390..87e31dd2c 100644 --- a/tox.ini +++ b/tox.ini @@ -175,7 +175,7 @@ deps = flake8-debugger==1.4.0 pep8-naming==0.3.3 flake8-putty==0.2.0 - ebb-lint==0.4.3 + ebb-lint==0.4.4 flake8-copyright==0.1 mccabe==0.3.1 pep8==1.7.0 From db6a0d53ca838a1ca7057066436a9e7333354192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Wed, 27 Jan 2016 10:04:24 +0100 Subject: [PATCH 08/24] Addressed code-quality remarks --- qutebrowser/browser/commands.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index b254efbcf..6092d3516 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1308,10 +1308,10 @@ class CommandDispatcher: raise cmdexc.CommandError("Element vanished while editing!") @cmdutils.register(instance='command-dispatcher', - modes=[KeyMode.insert], hide=True, scope='window') + modes=[KeyMode.insert], hide=True, scope='window', + needs_js=True) def paste_primary(self): - """Paste the primary selection at cursor position into the curently - selected form field. + """Paste the primary selection at cursor position. """ frame = self._current_widget().page().currentFrame() try: @@ -1324,14 +1324,14 @@ class CommandDispatcher: clipboard = QApplication.clipboard() if clipboard.supportsSelection(): sel = clipboard.text(QClipboard.Selection) - log.misc.debug("Pasting primary selection into element {} " - "(selection is '{}')".format(elem.debug_text(), sel)) + log.misc.debug("Pasting primary selection into element {}".format( + elem.debug_text())) elem.evaluateJavaScript(""" var sel = '{}'; var event = document.createEvent('TextEvent'); event.initTextEvent('textInput', true, true, null, sel); this.dispatchEvent(event); - """.format(sel)) + """.format(webelem.javascript_escape(sel))) def _clear_search(self, view, text): """Clear search string/highlights for the given view. From dcd62abe2b9bc4b5938d46b297fa877d48a44566 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 Jan 2016 22:20:07 +0100 Subject: [PATCH 09/24] tox: Update httpbin to 0.4.1. Added floating-point support for /delay endpoint --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 87e31dd2c..057222c83 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ deps = decorator==4.0.6 Flask==0.10.1 glob2==0.4.1 - httpbin==0.4.0 + httpbin==0.4.1 hypothesis==2.0.0 itsdangerous==0.24 Mako==1.0.3 From 2b6d35b9870d19af2f2e7c736994c1c3e68b3b5e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 Jan 2016 22:30:58 +0100 Subject: [PATCH 10/24] tox: Update mccabe to 0.4.0. - Stop testing on Python 3.2 - Add support for async/await keywords on Python 3.5 from PEP 0492 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 057222c83..5572292a6 100644 --- a/tox.ini +++ b/tox.ini @@ -177,7 +177,7 @@ deps = flake8-putty==0.2.0 ebb-lint==0.4.4 flake8-copyright==0.1 - mccabe==0.3.1 + mccabe==0.4.0 pep8==1.7.0 pyflakes==1.0.0 flake8-string-format==0.2.1 From b4972b3c08c5b6cffaed4d270afc0c2e9505c5e7 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 Jan 2016 22:32:21 +0100 Subject: [PATCH 11/24] tox: Update pytest-mock to 0.10.0. pytest-mock now monkeypatches the mock library to improve pytest output for failures of mock call assertions like Mock.assert_called_with(). --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5572292a6..54a530978 100644 --- a/tox.ini +++ b/tox.ini @@ -32,7 +32,7 @@ deps = pytest-cov==2.2.0 pytest-faulthandler==1.3.0 pytest-html==1.7 - pytest-mock==0.9.0 + pytest-mock==0.10.0 pytest-qt==1.11.0 pytest-instafail==0.3.0 pytest-travis-fold==1.2.0 From 6af1cce45f2caf64c57dc2f585f2f8eb86dccd16 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 28 Jan 2016 06:22:00 +0100 Subject: [PATCH 12/24] tox: Update pytest-mock to 0.10.1. - Fix regression in frozen tests due to distutils import dependency. - Fix regression when using pytest-mock with pytest-2.7.X. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 54a530978..f4a092cd4 100644 --- a/tox.ini +++ b/tox.ini @@ -32,7 +32,7 @@ deps = pytest-cov==2.2.0 pytest-faulthandler==1.3.0 pytest-html==1.7 - pytest-mock==0.10.0 + pytest-mock==0.10.1 pytest-qt==1.11.0 pytest-instafail==0.3.0 pytest-travis-fold==1.2.0 From b358566156e446c8048849e730f643fe2ab5534e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sat, 30 Jan 2016 13:57:26 +0100 Subject: [PATCH 13/24] Added tests for paste-primary command --- tests/integration/data/paste_primary.html | 10 ++++ tests/integration/features/yankpaste.feature | 50 ++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/integration/data/paste_primary.html diff --git a/tests/integration/data/paste_primary.html b/tests/integration/data/paste_primary.html new file mode 100644 index 000000000..ff6e9ed54 --- /dev/null +++ b/tests/integration/data/paste_primary.html @@ -0,0 +1,10 @@ + + + + + Paste primary selection + + + + + diff --git a/tests/integration/features/yankpaste.feature b/tests/integration/features/yankpaste.feature index b09bf7ce5..33704dfc1 100644 --- a/tests/integration/features/yankpaste.feature +++ b/tests/integration/features/yankpaste.feature @@ -170,3 +170,53 @@ Feature: Yanking and pasting. history: - active: true url: http://localhost:*/data/hello3.txt + + Scenario: Pasting the primary selection into an empty text field + When selection is supported + And I open data/paste_primary.html + And I put "Hello world" into the primary selection + # Click the text field + And I run :hint all + And I run :follow-hint a + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "Hello world" should be logged + + Scenario: Pasting the primary selection into a text field at specific position + When selection is supported + And I open data/paste_primary.html + And I run :jseval document.getElementById('qute-textarea').value = 'one two three four'; + And I put " Hello world" into the primary selection + # Click the text field + And I run :hint all + And I run :follow-hint a + # Move to the beginning and two words to the right + And I press the keys "" + And I press the key "" + And I press the key "" + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "one two Hello world three four" should be logged + + Scenario: Pasting the primary selection into a text field with undo + When selection is supported + And I open data/paste_primary.html + And I run :jseval document.getElementById('qute-textarea').value = 'one two three four'; + And I put " Hello world" into the primary selection + # Click the text field + And I run :hint all + And I run :follow-hint a + # Move to the beginning and after the first word + And I press the keys "" + And I press the key "" + # Paste and undo + And I run :paste-primary + And I press the key "" + # One word to the right + And I press the key "" + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "one two Hello world three four" should be logged From 5ec224d1f9cda4583108d99037852dd79e395267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sat, 30 Jan 2016 14:03:54 +0100 Subject: [PATCH 14/24] Simplified test for paste-primary command We don't need to move around for this test... --- tests/integration/features/yankpaste.feature | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/integration/features/yankpaste.feature b/tests/integration/features/yankpaste.feature index 33704dfc1..3001a54d3 100644 --- a/tests/integration/features/yankpaste.feature +++ b/tests/integration/features/yankpaste.feature @@ -203,20 +203,16 @@ Feature: Yanking and pasting. Scenario: Pasting the primary selection into a text field with undo When selection is supported And I open data/paste_primary.html - And I run :jseval document.getElementById('qute-textarea').value = 'one two three four'; - And I put " Hello world" into the primary selection # Click the text field And I run :hint all And I run :follow-hint a - # Move to the beginning and after the first word - And I press the keys "" - And I press the key "" # Paste and undo + And I put "This text should be undone" into the primary selection And I run :paste-primary And I press the key "" - # One word to the right - And I press the key "" + # Paste final text + And I put "This text should stay" into the primary selection And I run :paste-primary # Compare And I run :jseval console.log(document.getElementById('qute-textarea').value); - Then the javascript message "one two Hello world three four" should be logged + Then the javascript message "This text should stay" should be logged From cc8e7007b4b9831157d4e650170f313378ae3ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sat, 30 Jan 2016 14:13:41 +0100 Subject: [PATCH 15/24] Fixed docstring formatting error --- qutebrowser/browser/commands.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 6092d3516..da01cd06f 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1311,8 +1311,7 @@ class CommandDispatcher: modes=[KeyMode.insert], hide=True, scope='window', needs_js=True) def paste_primary(self): - """Paste the primary selection at cursor position. - """ + """Paste the primary selection at cursor position.""" frame = self._current_widget().page().currentFrame() try: elem = webelem.focus_elem(frame) From 39ca47168579928b8cba09f07d0f9da499bbf81d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2016 23:23:21 +0100 Subject: [PATCH 16/24] tox: Switch from pep257 to pydocstyle. Major Updates ------------- The project was renamed to pydocstyle and the new release will be 1.0.0! New Features ------------ - Added support for Python 3.5. - Classes nested inside classes are no longer considered private. Nested classes are considered public if their names are not prepended with an underscore and if their parent class is public, recursively. - Added the D403 error code - "First word of the first line should be properly capitalized". This new error is turned on by default. - Added support for .pydocstylerc and as configuration file name. Bug Fixes --------- - Fixed an issue where a NameError was raised when parsing complex definitions of __all__. - Fixed a bug where D202 was falsely reported when a function with just a docstring and no content was followed by a comment. - Fixed wrong __all__ definition in main module. - Fixed a bug where an AssertionError could occur when parsing __future__ imports. --- .travis.yml | 4 ++-- tox.ini | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6175a0b9..658bee4c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ env: - TESTENV=unittests-nodisp - TESTENV=misc - TESTENV=vulture - - TESTENV=pep257 + - TESTENV=pydocstyle - TESTENV=flake8 - TESTENV=pyroma - TESTENV=check-manifest @@ -53,7 +53,7 @@ matrix: - os: osx env: TESTENV=vulture - os: osx - env: TESTENV=pep257 + env: TESTENV=pydocstyle - os: osx env: TESTENV=flake8 - os: osx diff --git a/tox.ini b/tox.ini index f4a092cd4..da3ac8e4a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py34,py35-cov,misc,vulture,pep257,flake8,pylint,pyroma,check-manifest +envlist = py34,py35-cov,misc,vulture,pydocstyle,flake8,pylint,pyroma,check-manifest [testenv] # https://bitbucket.org/hpk42/tox/issue/246/ - only needed for Windows though @@ -150,21 +150,21 @@ commands = {envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {envpython} scripts/dev/run_pylint_on_tests.py --output-format=colorized --reports=no -[testenv:pep257] +[testenv:pydocstyle] basepython = python3 skip_install = true passenv = PYTHON LANG -deps = pep257==0.7.0 +deps = pydocstyle==1.0.0 # Disabled checks: # D102: Missing docstring in public method (will be handled by others) # D103: Missing docstring in public function (will be handled by others) # D104: Missing docstring in public package (will be handled by others) # D105: Missing docstring in magic method (will be handled by others) # D209: Blank line before closing """ (removed from PEP257) -# D211: Now b lank lines allowed before class docstring +# D211: No blank lines allowed before class docstring # (PEP257 got changed, but let's stick to the old standard) # D402: First line should not be function's signature (false-positives) -commands = {envpython} -m pep257 scripts tests qutebrowser --ignore=D102,D103,D104,D105,D209,D211,D402 '--match=(?!resources|test_*).*\.py' +commands = {envpython} -m pydocstyle scripts tests qutebrowser --ignore=D102,D103,D104,D105,D209,D211,D402 '--match=(?!resources|test_*).*\.py' [testenv:flake8] basepython = python3 From dc07f7ca9bf68785fe01829203d06e8af6a5ac51 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2016 23:30:12 +0100 Subject: [PATCH 17/24] Add a .pydocstylerc. --- .pydocstylerc | 13 +++++++++++++ MANIFEST.in | 1 + tox.ini | 11 +---------- 3 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 .pydocstylerc diff --git a/.pydocstylerc b/.pydocstylerc new file mode 100644 index 000000000..74eb0beff --- /dev/null +++ b/.pydocstylerc @@ -0,0 +1,13 @@ +[pydocstyle] +# Disabled checks: +# D102: Missing docstring in public method (will be handled by others) +# D103: Missing docstring in public function (will be handled by others) +# D104: Missing docstring in public package (will be handled by others) +# D105: Missing docstring in magic method (will be handled by others) +# D209: Blank line before closing """ (removed from PEP257) +# D211: No blank lines allowed before class docstring +# (PEP257 got changed, but let's stick to the old standard) +# D402: First line should not be function's signature (false-positives) +ignore = D102,D103,D104,D105,D209,D211,D402 +match = (?!resources|test_*).*\.py +inherit = false diff --git a/MANIFEST.in b/MANIFEST.in index e2dd15509..be33e3cfc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -32,6 +32,7 @@ exclude .eslintignore exclude doc/help exclude .appveyor.yml exclude .travis.yml +exclude .pydocstylerc exclude misc/appveyor_install.py global-exclude __pycache__ *.pyc *.pyo diff --git a/tox.ini b/tox.ini index da3ac8e4a..532cfb27b 100644 --- a/tox.ini +++ b/tox.ini @@ -155,16 +155,7 @@ basepython = python3 skip_install = true passenv = PYTHON LANG deps = pydocstyle==1.0.0 -# Disabled checks: -# D102: Missing docstring in public method (will be handled by others) -# D103: Missing docstring in public function (will be handled by others) -# D104: Missing docstring in public package (will be handled by others) -# D105: Missing docstring in magic method (will be handled by others) -# D209: Blank line before closing """ (removed from PEP257) -# D211: No blank lines allowed before class docstring -# (PEP257 got changed, but let's stick to the old standard) -# D402: First line should not be function's signature (false-positives) -commands = {envpython} -m pydocstyle scripts tests qutebrowser --ignore=D102,D103,D104,D105,D209,D211,D402 '--match=(?!resources|test_*).*\.py' +commands = {envpython} -m pydocstyle scripts tests qutebrowser [testenv:flake8] basepython = python3 From 67fd94b189ad308c0ed58a57a9953d37bafc7d5f Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2016 23:31:01 +0100 Subject: [PATCH 18/24] tox: Update check-manifest to 0.31. - Drop Python 3.2 support. - Ignore commented-out lines in MANIFEST.in. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 532cfb27b..73bb398e9 100644 --- a/tox.ini +++ b/tox.ini @@ -193,7 +193,7 @@ basepython = python3 skip_install = true passenv = deps = - check-manifest==0.30 + check-manifest==0.31 commands = {envdir}/bin/check-manifest --ignore 'qutebrowser/git-commit-id,qutebrowser/html/doc,qutebrowser/html/doc/*,*/__pycache__' From c9deee0835bab7b69d97d8392fe5185e3e9e02f5 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2016 23:32:29 +0100 Subject: [PATCH 19/24] tox: Update flake8 to 2.5.2. - Parse output_file and enable_extensions from config files - Raise upper bound on mccabe plugin to allow for version 0.4.0 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 73bb398e9..a73dc1ea8 100644 --- a/tox.ini +++ b/tox.ini @@ -162,7 +162,7 @@ basepython = python3 passenv = deps = -r{toxinidir}/requirements.txt - flake8==2.5.1 + flake8==2.5.2 flake8-debugger==1.4.0 pep8-naming==0.3.3 flake8-putty==0.2.0 From bf2adf19b23f6e19b63d47f48c260f28805ea367 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2016 23:33:17 +0100 Subject: [PATCH 20/24] tox: Update pytest-cov to 2.2.1. - Fixed incorrect merging of coverage data when xdist was used and coverage was >= 4.0. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a73dc1ea8..114e5f70f 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,7 @@ deps = pytest==2.8.7 pytest-bdd==2.16.0 pytest-catchlog==1.2.2 - pytest-cov==2.2.0 + pytest-cov==2.2.1 pytest-faulthandler==1.3.0 pytest-html==1.7 pytest-mock==0.10.1 From 30f68e55d690ad128d7cf7b7ca4511ddf7836ad4 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 Jan 2016 13:06:28 +0100 Subject: [PATCH 21/24] tox: Update xvfbwrapper to 0.2.8. - better error handling when xvfb is not installed - don't hardcode tmp dir location - use terminate instead of kill so Xvfb can clean up lock files --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 114e5f70f..fc1c421e9 100644 --- a/tox.ini +++ b/tox.ini @@ -42,7 +42,7 @@ deps = vulture==0.8.1 Werkzeug==0.11.3 wheel==0.26.0 - xvfbwrapper==0.2.7 + xvfbwrapper==0.2.8 cherrypy==4.0.0 commands = {envpython} scripts/link_pyqt.py --tox {envdir} From af5d199e8f820c59148081a703982095902cbfea Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 Jan 2016 20:56:37 +0100 Subject: [PATCH 22/24] bdd: Simplify :paste-primary tests. --- tests/integration/features/test_yankpaste.py | 13 +++++++++++++ tests/integration/features/yankpaste.feature | 13 ++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/integration/features/test_yankpaste.py b/tests/integration/features/test_yankpaste.py index 67f3df8db..7fce22a0e 100644 --- a/tests/integration/features/test_yankpaste.py +++ b/tests/integration/features/test_yankpaste.py @@ -38,3 +38,16 @@ def skip_with_broken_clipboard(qtbot, qapp): if clipboard.text() != "Does this work?": pytest.skip("Clipboard seems to be broken on this platform.") + + +@bdd.when(bdd.parsers.parse('I set the text field to "{value}"')) +def set_text_field(quteproc, value): + quteproc.send_cmd(":jseval document.getElementById('qute-textarea').value " + "= '{}';".format(value)) + + +@bdd.then(bdd.parsers.parse('the text field should contain "{value}"')) +def check_text_field(quteproc, value): + quteproc.send_cmd(":jseval console.log('text: ' + " + "document.getElementById('qute-textarea').value);") + quteproc.wait_for_js('text: ' + value) diff --git a/tests/integration/features/yankpaste.feature b/tests/integration/features/yankpaste.feature index 3001a54d3..99a34c35a 100644 --- a/tests/integration/features/yankpaste.feature +++ b/tests/integration/features/yankpaste.feature @@ -171,6 +171,8 @@ Feature: Yanking and pasting. - active: true url: http://localhost:*/data/hello3.txt + #### :paste-primary + Scenario: Pasting the primary selection into an empty text field When selection is supported And I open data/paste_primary.html @@ -180,13 +182,12 @@ Feature: Yanking and pasting. And I run :follow-hint a And I run :paste-primary # Compare - And I run :jseval console.log(document.getElementById('qute-textarea').value); - Then the javascript message "Hello world" should be logged + Then the text field should contain "Hello world" Scenario: Pasting the primary selection into a text field at specific position When selection is supported And I open data/paste_primary.html - And I run :jseval document.getElementById('qute-textarea').value = 'one two three four'; + And I set the text field to "one two three four" And I put " Hello world" into the primary selection # Click the text field And I run :hint all @@ -197,8 +198,7 @@ Feature: Yanking and pasting. And I press the key "" And I run :paste-primary # Compare - And I run :jseval console.log(document.getElementById('qute-textarea').value); - Then the javascript message "one two Hello world three four" should be logged + Then the text field should contain "one two Hello world three four" Scenario: Pasting the primary selection into a text field with undo When selection is supported @@ -214,5 +214,4 @@ Feature: Yanking and pasting. And I put "This text should stay" into the primary selection And I run :paste-primary # Compare - And I run :jseval console.log(document.getElementById('qute-textarea').value); - Then the javascript message "This text should stay" should be logged + Then the text field should contain "This text should stay" From 701cdc7f76e25e5a62a3da9c4c633a324952f426 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 Jan 2016 20:57:56 +0100 Subject: [PATCH 23/24] Update docs. --- CHANGELOG.asciidoc | 3 +++ README.asciidoc | 1 + doc/help/commands.asciidoc | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index a706d92dd..ffbfc971f 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -23,6 +23,9 @@ Added - New `--quiet` argument for the `:debug-pyeval` command to not open a tab with the results. Note `:debug-pyeval` is still only intended for debugging. - The completion now matches each entered word separately. +- A new command `:paste-primary` got added to paste the primary selection, and + `` got added as a binding so it pastes primary rather than + clipboard. Changed ~~~~~~~ diff --git a/README.asciidoc b/README.asciidoc index d8cd6fb81..c1fd83ca0 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -165,6 +165,7 @@ Contributors, sorted by the number of commits in descending order: * Jonas Schürmann * Panagiotis Ktistakis * Jimmy +* Jakub Klinkovský * skinnay * error800 * Zach-Button diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index ddbd2c8ac..8e3b00b1b 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -833,6 +833,7 @@ How many steps to zoom out. |<>|Move the cursor or selection to the start of next block. |<>|Move the cursor or selection to the start of previous block. |<>|Open an external editor with the currently selected form field. +|<>|Paste the primary selection at cursor position. |<>|Accept the current prompt. |<>|Answer no to a yes/no prompt. |<>|Answer yes to a yes/no prompt. @@ -1046,6 +1047,10 @@ Open an external editor with the currently selected form field. The editor which should be launched can be configured via the `general -> editor` config option. +[[paste-primary]] +=== paste-primary +Paste the primary selection at cursor position. + [[prompt-accept]] === prompt-accept Accept the current prompt. From d50e1be56671bf064b25d2c27a21f4d75c3af194 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 Jan 2016 22:08:46 +0100 Subject: [PATCH 24/24] Add some more :paste-primary tests. --- tests/integration/data/paste_primary.html | 1 + tests/integration/features/yankpaste.feature | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/integration/data/paste_primary.html b/tests/integration/data/paste_primary.html index ff6e9ed54..4f803aedf 100644 --- a/tests/integration/data/paste_primary.html +++ b/tests/integration/data/paste_primary.html @@ -6,5 +6,6 @@ + diff --git a/tests/integration/features/yankpaste.feature b/tests/integration/features/yankpaste.feature index 99a34c35a..40255b6e5 100644 --- a/tests/integration/features/yankpaste.feature +++ b/tests/integration/features/yankpaste.feature @@ -215,3 +215,22 @@ Feature: Yanking and pasting. And I run :paste-primary # Compare Then the text field should contain "This text should stay" + + Scenario: Pasting the primary selection without a focused field + When selection is supported + And I open data/paste_primary.html + And I put "test" into the primary selection + And I run :enter-mode insert + And I run :paste-primary + Then the error "No element focused!" should be shown + + Scenario: Pasting the primary selection with a read-only field + When selection is supported + And I open data/paste_primary.html + # Click the text field + And I run :hint all + And I run :follow-hint s + And I put "test" into the primary selection + And I run :enter-mode insert + And I run :paste-primary + Then the error "Focused element is not editable!" should be shown