Add a history.exclude setting

This allows to exclude URL patterns from being displayed in the completion or
in qute://history.
This commit is contained in:
Florian Bruhin 2018-09-01 16:29:38 +02:00
parent 7fb2224640
commit 71a2dad570
6 changed files with 94 additions and 10 deletions

View File

@ -205,6 +205,7 @@
|<<hints.prev_regexes,hints.prev_regexes>>|Comma-separated list of regular expressions to use for 'prev' links.
|<<hints.scatter,hints.scatter>>|Scatter hint key chains (like Vimium) or not (like dwb).
|<<hints.uppercase,hints.uppercase>>|Make characters in hint strings uppercase.
|<<history.exclude,history.exclude>>|A list of patterns which should not be shown in the history.
|<<history.gap_interval,history.gap_interval>>|Maximum time (in minutes) between two history items for them to be considered being from the same browsing session.
|<<input.escape_quits_reporter,input.escape_quits_reporter>>|Allow Escape to quit the crash reporter.
|<<input.forward_unbound_keys,input.forward_unbound_keys>>|Which unbound keys to forward to the webview in normal mode.
@ -2509,6 +2510,17 @@ Type: <<types,Bool>>
Default: +pass:[false]+
[[history.exclude]]
=== history.exclude
A list of patterns which should not be shown in the history.
This only affects the completion and qute://history page. Matching URLs are still saved in the history, but hidden.
Changing this setting will cause the completion history to be regenerated on the next start, which will take a short while.
This setting requires a restart.
Type: <<types,List of UrlPattern>>
Default: empty
[[history.gap_interval]]
=== history.gap_interval
Maximum time (in minutes) between two history items for them to be considered being from the same browsing session.

View File

@ -25,6 +25,7 @@ import contextlib
from PyQt5.QtCore import pyqtSlot, QUrl, QTimer, pyqtSignal
from qutebrowser.config import config
from qutebrowser.commands import cmdutils, cmdexc
from qutebrowser.utils import (utils, objreg, log, usertypes, message,
debug, standarddir, qtutils)
@ -128,12 +129,18 @@ class WebHistory(sql.SqlTable):
'ORDER BY atime desc '
'limit :limit offset :offset')
config.instance.changed.connect(self._on_config_changed)
def __repr__(self):
return utils.get_repr(self, length=len(self))
def __contains__(self, url):
return self._contains_query.run(val=url).value()
@config.change_filter('history.exclude')
def _on_config_changed(self):
self.metainfo['force_rebuild'] = True
@contextlib.contextmanager
def _handle_sql_errors(self):
try:
@ -151,9 +158,14 @@ class WebHistory(sql.SqlTable):
'WHERE NOT redirect and url NOT LIKE "qute://back%" '
'GROUP BY url ORDER BY atime asc')
for entry in q.run():
data['url'].append(self._format_completion_url(QUrl(entry.url)))
url = QUrl(entry.url)
if any(pattern.matches(url)
for pattern in config.val.history.exclude):
continue
data['url'].append(self._format_completion_url(url))
data['title'].append(entry.title)
data['last_atime'].append(entry.atime)
self.completion.insert_batch(data, replace=True)
sql.Query('pragma user_version = {}'.format(_USER_VERSION)).run()
@ -259,12 +271,18 @@ class WebHistory(sql.SqlTable):
'title': title,
'atime': atime,
'redirect': redirect})
if not redirect:
self.completion.insert({
'url': self._format_completion_url(url),
'title': title,
'last_atime': atime
}, replace=True)
if any(pattern.matches(url)
for pattern in config.val.history.exclude):
return
if redirect:
return
self.completion.insert({
'url': self._format_completion_url(url),
'title': title,
'last_atime': atime
}, replace=True)
def _parse_entry(self, line):
"""Parse a history line like '12345 http://example.com title'."""

View File

@ -251,7 +251,10 @@ def history_data(start_time, offset=None):
return [{"url": e.url,
"title": html.escape(e.title) or html.escape(e.url),
"time": e.atime} for e in entries]
"time": e.atime}
for e in entries
if not any(pattern.matches(QUrl(e.url))
for pattern in config.val.history.exclude)]
@add_handler('history')

View File

@ -1055,6 +1055,22 @@ history.gap_interval:
Items with less time between them are grouped when being displayed in
`:history`. Use -1 to disable separation.
history.exclude:
type:
name: List
valtype: UrlPattern
none_ok: true
default: []
restart: true
desc: >-
A list of patterns which should not be shown in the history.
This only affects the completion and qute://history page. Matching URLs are
still saved in the history, but hidden.
Changing this setting will cause the completion history to be regenerated
on the next start, which will take a short while.
## input
input.escape_quits_reporter:

View File

@ -221,6 +221,14 @@ class TestAdd:
hist.add_from_tab(QUrl(url), QUrl(req_url), 'title')
assert set(hist) == set(expected)
def test_exclude(self, hist, config_stub):
"""Excluded URLs should be in the history but not completion."""
config_stub.set_obj('history.exclude', ['*.example.org'])
url = QUrl('http://www.example.org/')
hist.add_from_tab(url, url, 'title')
assert list(hist)
assert not list(hist.completion)
class TestHistoryInterface:
@ -472,6 +480,21 @@ class TestRebuild:
]
assert not hist3.metainfo['force_rebuild']
def test_exclude(self, config_stub, hist):
"""Ensure that patterns in history.exclude are ignored."""
config_stub.set_obj('history.exclude', ['*.example.org'])
assert hist.metainfo['force_rebuild']
hist.add_url(QUrl('http://example.com'), redirect=False, atime=1)
hist.add_url(QUrl('http://example.org'), redirect=False, atime=2)
hist2 = history.WebHistory()
assert list(hist2.completion) == [('http://example.com', '', 1)]
def test_unrelated_config_change(self, config_stub, hist):
config_stub.set_obj('history.gap_interval', 1234)
assert not hist.metainfo['force_rebuild']
class TestCompletionMetaInfo:

View File

@ -90,14 +90,15 @@ class TestHistoryHandler:
for i in range(entry_count):
entry_atime = now - i * interval
entry = {"atime": str(entry_atime),
"url": QUrl("www.x.com/" + str(i)),
"url": QUrl("http://www.x.com/" + str(i)),
"title": "Page " + str(i)}
items.insert(0, entry)
return items
@pytest.fixture
def fake_web_history(self, fake_save_manager, tmpdir, init_sql):
def fake_web_history(self, fake_save_manager, tmpdir, init_sql,
config_stub):
"""Create a fake web-history and register it into objreg."""
web_history = history.WebHistory()
objreg.register('web-history', web_history)
@ -133,6 +134,17 @@ class TestHistoryHandler:
assert item['time'] <= start_time
assert item['time'] > end_time
def test_exclude(self, fake_web_history, now, config_stub):
config_stub.set_obj('history.exclude', ['www.x.com'])
url = QUrl('http://www.example.org/')
fake_web_history.add_from_tab(url, url, 'title')
url = QUrl("qute://history/data?start_time={}".format(now))
_mimetype, data = qutescheme.qute_history(url)
items = json.loads(data)
assert len(items) == 1
assert items[0]['url'] == 'http://www.example.org/'
def test_qute_history_benchmark(self, fake_web_history, benchmark, now):
r = range(100000)
entries = {