Merge branch 'EliteTK-history-clear'
This commit is contained in:
commit
a5a4c17b1f
@ -34,6 +34,7 @@ Added
|
|||||||
pressed. This can be turned off using `:set ui keyhint-blacklist *`.
|
pressed. This can be turned off using `:set ui keyhint-blacklist *`.
|
||||||
- New `hints -> auto-follow-timeout` setting to ignore keypresses after
|
- New `hints -> auto-follow-timeout` setting to ignore keypresses after
|
||||||
following a hint when filtering in number mode.
|
following a hint when filtering in number mode.
|
||||||
|
- New `:history-clear` command to clear the entire history
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
@ -188,6 +188,7 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* sbinix
|
* sbinix
|
||||||
* neeasade
|
* neeasade
|
||||||
* jnphilipp
|
* jnphilipp
|
||||||
|
* Tomasz Kramkowski
|
||||||
* Tobias Patzl
|
* Tobias Patzl
|
||||||
* Stefan Tatschner
|
* Stefan Tatschner
|
||||||
* Peter Michely
|
* Peter Michely
|
||||||
@ -211,7 +212,6 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* evan
|
* evan
|
||||||
* dylan araps
|
* dylan araps
|
||||||
* Xitian9
|
* Xitian9
|
||||||
* Tomasz Kramkowski
|
|
||||||
* Tomas Orsava
|
* Tomas Orsava
|
||||||
* Tobias Werth
|
* Tobias Werth
|
||||||
* Tim Harder
|
* Tim Harder
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|<<fullscreen,fullscreen>>|Toggle fullscreen mode.
|
|<<fullscreen,fullscreen>>|Toggle fullscreen mode.
|
||||||
|<<help,help>>|Show help about a command or setting.
|
|<<help,help>>|Show help about a command or setting.
|
||||||
|<<hint,hint>>|Start hinting.
|
|<<hint,hint>>|Start hinting.
|
||||||
|
|<<history-clear,history-clear>>|Clear all history entries.
|
||||||
|<<home,home>>|Open main startpage in current tab.
|
|<<home,home>>|Open main startpage in current tab.
|
||||||
|<<inspector,inspector>>|Toggle the web inspector.
|
|<<inspector,inspector>>|Toggle the web inspector.
|
||||||
|<<jseval,jseval>>|Evaluate a JavaScript string.
|
|<<jseval,jseval>>|Evaluate a JavaScript string.
|
||||||
@ -356,6 +357,10 @@ Start hinting.
|
|||||||
==== note
|
==== note
|
||||||
* This command does not split arguments after the last argument and handles quotes literally.
|
* This command does not split arguments after the last argument and handles quotes literally.
|
||||||
|
|
||||||
|
[[history-clear]]
|
||||||
|
=== history-clear
|
||||||
|
Clear all history entries.
|
||||||
|
|
||||||
[[home]]
|
[[home]]
|
||||||
=== home
|
=== home
|
||||||
Open main startpage in current tab.
|
Open main startpage in current tab.
|
||||||
|
@ -25,6 +25,7 @@ import collections
|
|||||||
from PyQt5.QtCore import pyqtSignal, QUrl
|
from PyQt5.QtCore import pyqtSignal, QUrl
|
||||||
from PyQt5.QtWebKit import QWebHistoryInterface
|
from PyQt5.QtWebKit import QWebHistoryInterface
|
||||||
|
|
||||||
|
from qutebrowser.commands import cmdutils
|
||||||
from qutebrowser.utils import utils, objreg, standarddir, log
|
from qutebrowser.utils import utils, objreg, standarddir, log
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.misc import lineparser
|
from qutebrowser.misc import lineparser
|
||||||
@ -72,10 +73,12 @@ class WebHistory(QWebHistoryInterface):
|
|||||||
arg: The new HistoryEntry.
|
arg: The new HistoryEntry.
|
||||||
item_added: Emitted after a new HistoryEntry is added.
|
item_added: Emitted after a new HistoryEntry is added.
|
||||||
arg: The new HistoryEntry.
|
arg: The new HistoryEntry.
|
||||||
|
cleared: Emitted after the history is cleared.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
add_completion_item = pyqtSignal(HistoryEntry)
|
add_completion_item = pyqtSignal(HistoryEntry)
|
||||||
item_added = pyqtSignal(HistoryEntry)
|
item_added = pyqtSignal(HistoryEntry)
|
||||||
|
cleared = pyqtSignal()
|
||||||
async_read_done = pyqtSignal()
|
async_read_done = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@ -169,6 +172,16 @@ class WebHistory(QWebHistoryInterface):
|
|||||||
self._lineparser.save()
|
self._lineparser.save()
|
||||||
self._saved_count = len(self._new_history)
|
self._saved_count = len(self._new_history)
|
||||||
|
|
||||||
|
@cmdutils.register(name='history-clear', instance='web-history')
|
||||||
|
def clear(self):
|
||||||
|
"""Clear all history entries."""
|
||||||
|
self._lineparser.clear()
|
||||||
|
self._history_dict.clear()
|
||||||
|
self._temp_history.clear()
|
||||||
|
self._new_history.clear()
|
||||||
|
self._saved_count = 0
|
||||||
|
self.cleared.emit()
|
||||||
|
|
||||||
def addHistoryEntry(self, url_string):
|
def addHistoryEntry(self, url_string):
|
||||||
"""Called by WebKit when an URL should be added to the history.
|
"""Called by WebKit when an URL should be added to the history.
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ class UrlCompletionModel(base.BaseCompletionModel):
|
|||||||
for entry in history:
|
for entry in history:
|
||||||
self._add_history_entry(entry)
|
self._add_history_entry(entry)
|
||||||
self._history.add_completion_item.connect(self.on_history_item_added)
|
self._history.add_completion_item.connect(self.on_history_item_added)
|
||||||
|
self._history.cleared.connect(self.on_history_cleared)
|
||||||
|
|
||||||
objreg.get('config').changed.connect(self.reformat_timestamps)
|
objreg.get('config').changed.connect(self.reformat_timestamps)
|
||||||
|
|
||||||
@ -130,6 +131,10 @@ class UrlCompletionModel(base.BaseCompletionModel):
|
|||||||
else:
|
else:
|
||||||
self._add_history_entry(entry)
|
self._add_history_entry(entry)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def on_history_cleared(self):
|
||||||
|
self._history_cat.removeRows(0, self._history_cat.rowCount())
|
||||||
|
|
||||||
def _remove_item(self, data, category, column):
|
def _remove_item(self, data, category, column):
|
||||||
"""Helper function for on_quickmark_removed and on_bookmark_removed.
|
"""Helper function for on_quickmark_removed and on_bookmark_removed.
|
||||||
|
|
||||||
|
@ -114,6 +114,8 @@ class BaseLineParser(QObject):
|
|||||||
fp: A file object to write the data to.
|
fp: A file object to write the data to.
|
||||||
data: The data to write.
|
data: The data to write.
|
||||||
"""
|
"""
|
||||||
|
if not data:
|
||||||
|
return
|
||||||
if self._binary:
|
if self._binary:
|
||||||
fp.write(b'\n'.join(data))
|
fp.write(b'\n'.join(data))
|
||||||
fp.write(b'\n')
|
fp.write(b'\n')
|
||||||
@ -125,6 +127,10 @@ class BaseLineParser(QObject):
|
|||||||
"""Save the history to disk."""
|
"""Save the history to disk."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Clear the contents of the file."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class AppendLineParser(BaseLineParser):
|
class AppendLineParser(BaseLineParser):
|
||||||
|
|
||||||
@ -183,6 +189,15 @@ class AppendLineParser(BaseLineParser):
|
|||||||
self.new_data = []
|
self.new_data = []
|
||||||
self._after_save()
|
self._after_save()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
do_save = self._prepare_save()
|
||||||
|
if not do_save:
|
||||||
|
return
|
||||||
|
with self._open('w'):
|
||||||
|
pass
|
||||||
|
self.new_data = []
|
||||||
|
self._after_save()
|
||||||
|
|
||||||
|
|
||||||
class LineParser(BaseLineParser):
|
class LineParser(BaseLineParser):
|
||||||
|
|
||||||
@ -237,6 +252,10 @@ class LineParser(BaseLineParser):
|
|||||||
self._opened = False
|
self._opened = False
|
||||||
self._after_save()
|
self._after_save()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.data = []
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
class LimitLineParser(LineParser):
|
class LimitLineParser(LineParser):
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@ class LineparserSaveStub(lineparser.BaseLineParser):
|
|||||||
def save(self):
|
def save(self):
|
||||||
self.saved = self.data
|
self.saved = self.data
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.data)
|
return iter(self.data)
|
||||||
|
|
||||||
|
@ -19,80 +19,11 @@
|
|||||||
|
|
||||||
"""Tests for qutebrowser.misc.lineparser."""
|
"""Tests for qutebrowser.misc.lineparser."""
|
||||||
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qutebrowser.misc import lineparser as lineparsermod
|
from qutebrowser.misc import lineparser as lineparsermod
|
||||||
|
|
||||||
|
|
||||||
class LineParserMixin:
|
|
||||||
|
|
||||||
"""A wrapper over lineparser.BaseLineParser to make it testable."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self._data = None
|
|
||||||
self._test_save_prepared = False
|
|
||||||
|
|
||||||
def _open(self, mode):
|
|
||||||
"""Override _open to use StringIO/BytesIO instead of a real file."""
|
|
||||||
if mode not in 'rwa':
|
|
||||||
raise ValueError("Unknown mode {!r}!".format(mode))
|
|
||||||
if self._test_save_prepared:
|
|
||||||
self._test_save_prepared = False
|
|
||||||
elif mode != 'r':
|
|
||||||
raise ValueError("Doing unprepared save!")
|
|
||||||
|
|
||||||
if mode in 'ar' and self._data is not None:
|
|
||||||
prev_val = self._data
|
|
||||||
else:
|
|
||||||
prev_val = None
|
|
||||||
|
|
||||||
if self._binary:
|
|
||||||
fobj = io.BytesIO(prev_val)
|
|
||||||
else:
|
|
||||||
fobj = io.StringIO(prev_val)
|
|
||||||
|
|
||||||
if mode == 'a':
|
|
||||||
fobj.seek(0, os.SEEK_END)
|
|
||||||
return fobj
|
|
||||||
|
|
||||||
def _write(self, fp, data):
|
|
||||||
"""Extend _write to get the data after writing it."""
|
|
||||||
super()._write(fp, data)
|
|
||||||
self._data = fp.getvalue()
|
|
||||||
|
|
||||||
def _prepare_save(self):
|
|
||||||
"""Keep track if _prepare_save has been called."""
|
|
||||||
self._test_save_prepared = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class AppendLineParserTestable(LineParserMixin,
|
|
||||||
lineparsermod.AppendLineParser):
|
|
||||||
|
|
||||||
"""Wrapper over AppendLineParser to make it testable."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineParserTestable(LineParserMixin, lineparsermod.LineParser):
|
|
||||||
|
|
||||||
"""Wrapper over LineParser to make it testable."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LimitLineParserTestable(LineParserMixin,
|
|
||||||
lineparsermod.LimitLineParser):
|
|
||||||
|
|
||||||
"""Wrapper over LimitLineParser to make it testable."""
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestBaseLineParser:
|
class TestBaseLineParser:
|
||||||
|
|
||||||
"""Tests for BaseLineParser."""
|
"""Tests for BaseLineParser."""
|
||||||
@ -122,6 +53,24 @@ class TestBaseLineParser:
|
|||||||
os_mock.makedirs.assert_called_with(self.CONFDIR, 0o755)
|
os_mock.makedirs.assert_called_with(self.CONFDIR, 0o755)
|
||||||
|
|
||||||
|
|
||||||
|
class TestLineParser:
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def lineparser(self, tmpdir):
|
||||||
|
"""Fixture to get a LineParser for tests."""
|
||||||
|
lp = lineparsermod.LineParser(str(tmpdir), 'file')
|
||||||
|
lp.save()
|
||||||
|
return lp
|
||||||
|
|
||||||
|
def test_clear(self, tmpdir, lineparser):
|
||||||
|
lineparser.data = ['one', 'two']
|
||||||
|
lineparser.save()
|
||||||
|
assert (tmpdir / 'file').read() == 'one\ntwo\n'
|
||||||
|
lineparser.clear()
|
||||||
|
assert not lineparser.data
|
||||||
|
assert (tmpdir / 'file').read() == ''
|
||||||
|
|
||||||
|
|
||||||
class TestAppendLineParser:
|
class TestAppendLineParser:
|
||||||
|
|
||||||
"""Tests for AppendLineParser."""
|
"""Tests for AppendLineParser."""
|
||||||
@ -129,9 +78,9 @@ class TestAppendLineParser:
|
|||||||
BASE_DATA = ['old data 1', 'old data 2']
|
BASE_DATA = ['old data 1', 'old data 2']
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def lineparser(self):
|
def lineparser(self, tmpdir):
|
||||||
"""Fixture to get an AppendLineParser for tests."""
|
"""Fixture to get an AppendLineParser for tests."""
|
||||||
lp = AppendLineParserTestable('this really', 'does not matter')
|
lp = lineparsermod.AppendLineParser(str(tmpdir), 'file')
|
||||||
lp.new_data = self.BASE_DATA
|
lp.new_data = self.BASE_DATA
|
||||||
lp.save()
|
lp.save()
|
||||||
return lp
|
return lp
|
||||||
@ -140,12 +89,23 @@ class TestAppendLineParser:
|
|||||||
"""Get the expected data with newlines."""
|
"""Get the expected data with newlines."""
|
||||||
return '\n'.join(self.BASE_DATA + new_data) + '\n'
|
return '\n'.join(self.BASE_DATA + new_data) + '\n'
|
||||||
|
|
||||||
def test_save(self, lineparser):
|
def test_save(self, tmpdir, lineparser):
|
||||||
"""Test save()."""
|
"""Test save()."""
|
||||||
new_data = ['new data 1', 'new data 2']
|
new_data = ['new data 1', 'new data 2']
|
||||||
lineparser.new_data = new_data
|
lineparser.new_data = new_data
|
||||||
lineparser.save()
|
lineparser.save()
|
||||||
assert lineparser._data == self._get_expected(new_data)
|
assert (tmpdir / 'file').read() == self._get_expected(new_data)
|
||||||
|
|
||||||
|
def test_clear(self, tmpdir, lineparser):
|
||||||
|
lineparser.new_data = ['one', 'two']
|
||||||
|
lineparser.save()
|
||||||
|
assert (tmpdir / 'file').read() == "old data 1\nold data 2\none\ntwo\n"
|
||||||
|
|
||||||
|
lineparser.new_data = ['one', 'two']
|
||||||
|
lineparser.clear()
|
||||||
|
lineparser.save()
|
||||||
|
assert not lineparser.new_data
|
||||||
|
assert (tmpdir / 'file').read() == ""
|
||||||
|
|
||||||
def test_iter_without_open(self, lineparser):
|
def test_iter_without_open(self, lineparser):
|
||||||
"""Test __iter__ without having called open()."""
|
"""Test __iter__ without having called open()."""
|
||||||
@ -170,9 +130,10 @@ class TestAppendLineParser:
|
|||||||
with linep.open():
|
with linep.open():
|
||||||
assert list(linep) == new_data
|
assert list(linep) == new_data
|
||||||
|
|
||||||
def test_get_recent_none(self):
|
def test_get_recent_none(self, tmpdir):
|
||||||
"""Test get_recent with no data."""
|
"""Test get_recent with no data."""
|
||||||
linep = AppendLineParserTestable('this really', 'does not matter')
|
(tmpdir / 'file2').ensure()
|
||||||
|
linep = lineparsermod.AppendLineParser(str(tmpdir), 'file2')
|
||||||
assert linep.get_recent() == []
|
assert linep.get_recent() == []
|
||||||
|
|
||||||
def test_get_recent_little(self, lineparser):
|
def test_get_recent_little(self, lineparser):
|
||||||
|
Loading…
Reference in New Issue
Block a user