diff --git a/qutebrowser/misc/editor.py b/qutebrowser/misc/editor.py index f300bc2e1..6752a37e3 100644 --- a/qutebrowser/misc/editor.py +++ b/qutebrowser/misc/editor.py @@ -51,6 +51,7 @@ class ExternalEditor(QObject): self._proc = None self._remove_file = None self._watcher = QFileSystemWatcher(parent=self) + self._content = None def _cleanup(self): """Clean up temporary files after the editor closed.""" @@ -79,6 +80,8 @@ class ExternalEditor(QObject): # No error/cleanup here, since we already handle this in # on_proc_error. return + # do a final read to make sure we don't miss the last signal + self._on_file_changed(self._filename) self._cleanup() @pyqtSlot(QProcess.ProcessError) @@ -128,7 +131,10 @@ class ExternalEditor(QObject): message.error("Failed to read back edited file: {}".format(e)) return log.procs.debug("Read back: {}".format(text)) - self.file_updated.emit(text) + if self._content != text: + self._content = text + self.file_updated.emit(text) + def edit_file(self, filename): """Edit the file with the given filename.""" diff --git a/tests/unit/misc/test_editor.py b/tests/unit/misc/test_editor.py index b0ddbff25..3f7d8acaf 100644 --- a/tests/unit/misc/test_editor.py +++ b/tests/unit/misc/test_editor.py @@ -129,10 +129,7 @@ class TestFileHandling: pytest.skip("File was still readable") with caplog.at_level(logging.ERROR): - with qtbot.wait_signal(editor._watcher.fileChanged): - with open(filename, 'w', encoding='utf-8') as f: - f.write('unreadable') - editor._proc.finished.emit(0, QProcess.NormalExit) + editor._proc.finished.emit(0, QProcess.NormalExit) assert not os.path.exists(filename) msg = message_mock.getmsg(usertypes.MessageLevel.error) assert msg.text.startswith("Failed to read back edited file: ") @@ -177,11 +174,30 @@ def test_modify(qtbot, editor, initial_text, edited_text): with open(editor._filename, 'w', encoding='utf-8') as f: f.write(edited_text) - editor._proc.finished.emit(0, QProcess.NormalExit) + with qtbot.assert_not_emitted(editor.file_updated): + editor._proc.finished.emit(0, QProcess.NormalExit) assert blocker.args == [edited_text] +def test_modify_multiple(qtbot, editor): + """Test that multiple saves all trigger file_updated.""" + editor.edit('foo') + + with qtbot.wait_signal(editor.file_updated) as blocker: + with open(editor._filename, 'w', encoding='utf-8') as f: + f.write('bar') + assert blocker.args == ['bar'] + + with qtbot.wait_signal(editor.file_updated) as blocker: + with open(editor._filename, 'w', encoding='utf-8') as f: + f.write('baz') + assert blocker.args == ['baz'] + + with qtbot.assert_not_emitted(editor.file_updated): + editor._proc.finished.emit(0, QProcess.NormalExit) + + @pytest.mark.parametrize('text, caret_position, result', [ ('', 0, (1, 1)), ('a', 0, (1, 1)),