Merge branch 'EliteTK-history-clear'

This commit is contained in:
Florian Bruhin 2016-06-08 11:40:00 +02:00
commit a5a4c17b1f
8 changed files with 83 additions and 76 deletions

View File

@ -34,6 +34,7 @@ Added
pressed. This can be turned off using `:set ui keyhint-blacklist *`.
- New `hints -> auto-follow-timeout` setting to ignore keypresses after
following a hint when filtering in number mode.
- New `:history-clear` command to clear the entire history
Changed
~~~~~~~

View File

@ -188,6 +188,7 @@ Contributors, sorted by the number of commits in descending order:
* sbinix
* neeasade
* jnphilipp
* Tomasz Kramkowski
* Tobias Patzl
* Stefan Tatschner
* Peter Michely
@ -211,7 +212,6 @@ Contributors, sorted by the number of commits in descending order:
* evan
* dylan araps
* Xitian9
* Tomasz Kramkowski
* Tomas Orsava
* Tobias Werth
* Tim Harder

View File

@ -26,6 +26,7 @@
|<<fullscreen,fullscreen>>|Toggle fullscreen mode.
|<<help,help>>|Show help about a command or setting.
|<<hint,hint>>|Start hinting.
|<<history-clear,history-clear>>|Clear all history entries.
|<<home,home>>|Open main startpage in current tab.
|<<inspector,inspector>>|Toggle the web inspector.
|<<jseval,jseval>>|Evaluate a JavaScript string.
@ -356,6 +357,10 @@ Start hinting.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[history-clear]]
=== history-clear
Clear all history entries.
[[home]]
=== home
Open main startpage in current tab.

View File

@ -25,6 +25,7 @@ import collections
from PyQt5.QtCore import pyqtSignal, QUrl
from PyQt5.QtWebKit import QWebHistoryInterface
from qutebrowser.commands import cmdutils
from qutebrowser.utils import utils, objreg, standarddir, log
from qutebrowser.config import config
from qutebrowser.misc import lineparser
@ -72,10 +73,12 @@ class WebHistory(QWebHistoryInterface):
arg: The new HistoryEntry.
item_added: Emitted after a new HistoryEntry is added.
arg: The new HistoryEntry.
cleared: Emitted after the history is cleared.
"""
add_completion_item = pyqtSignal(HistoryEntry)
item_added = pyqtSignal(HistoryEntry)
cleared = pyqtSignal()
async_read_done = pyqtSignal()
def __init__(self, parent=None):
@ -169,6 +172,16 @@ class WebHistory(QWebHistoryInterface):
self._lineparser.save()
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):
"""Called by WebKit when an URL should be added to the history.

View File

@ -76,6 +76,7 @@ class UrlCompletionModel(base.BaseCompletionModel):
for entry in history:
self._add_history_entry(entry)
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)
@ -130,6 +131,10 @@ class UrlCompletionModel(base.BaseCompletionModel):
else:
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):
"""Helper function for on_quickmark_removed and on_bookmark_removed.

View File

@ -114,6 +114,8 @@ class BaseLineParser(QObject):
fp: A file object to write the data to.
data: The data to write.
"""
if not data:
return
if self._binary:
fp.write(b'\n'.join(data))
fp.write(b'\n')
@ -125,6 +127,10 @@ class BaseLineParser(QObject):
"""Save the history to disk."""
raise NotImplementedError
def clear(self):
"""Clear the contents of the file."""
raise NotImplementedError
class AppendLineParser(BaseLineParser):
@ -183,6 +189,15 @@ class AppendLineParser(BaseLineParser):
self.new_data = []
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):
@ -237,6 +252,10 @@ class LineParser(BaseLineParser):
self._opened = False
self._after_save()
def clear(self):
self.data = []
self.save()
class LimitLineParser(LineParser):

View File

@ -57,6 +57,9 @@ class LineparserSaveStub(lineparser.BaseLineParser):
def save(self):
self.saved = self.data
def clear(self):
pass
def __iter__(self):
return iter(self.data)

View File

@ -19,80 +19,11 @@
"""Tests for qutebrowser.misc.lineparser."""
import io
import os
import pytest
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:
"""Tests for BaseLineParser."""
@ -122,6 +53,24 @@ class TestBaseLineParser:
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:
"""Tests for AppendLineParser."""
@ -129,9 +78,9 @@ class TestAppendLineParser:
BASE_DATA = ['old data 1', 'old data 2']
@pytest.fixture
def lineparser(self):
def lineparser(self, tmpdir):
"""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.save()
return lp
@ -140,12 +89,23 @@ class TestAppendLineParser:
"""Get the expected data with newlines."""
return '\n'.join(self.BASE_DATA + new_data) + '\n'
def test_save(self, lineparser):
def test_save(self, tmpdir, lineparser):
"""Test save()."""
new_data = ['new data 1', 'new data 2']
lineparser.new_data = new_data
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):
"""Test __iter__ without having called open()."""
@ -170,9 +130,10 @@ class TestAppendLineParser:
with linep.open():
assert list(linep) == new_data
def test_get_recent_none(self):
def test_get_recent_none(self, tmpdir):
"""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() == []
def test_get_recent_little(self, lineparser):