From 33a2181e318ae2a9558ecaeafecd168467f8b5fe Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 1 Feb 2015 17:34:16 +0100 Subject: [PATCH] Record global page history to disk. We currently don't do anything with it yet, but people could use it in scripts already and we have the history later when completion or other stuff will be added based on it. See #33. --- .pylintrc | 3 +- qutebrowser/app.py | 14 ++-- qutebrowser/browser/history.py | 114 +++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 qutebrowser/browser/history.py diff --git a/.pylintrc b/.pylintrc index 8498bea12..79fb9f860 100644 --- a/.pylintrc +++ b/.pylintrc @@ -25,7 +25,8 @@ disable=no-self-use, unnecessary-lambda, blacklisted-name, too-many-lines, - logging-format-interpolation + logging-format-interpolation, + interface-not-implemented [BASIC] module-rgx=(__)?[a-z][a-z0-9_]*(__)?$ diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 2eca4c9dc..a21c54800 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -40,7 +40,7 @@ import qutebrowser import qutebrowser.resources # pylint: disable=unused-import from qutebrowser.commands import cmdutils, runners from qutebrowser.config import style, config, websettings -from qutebrowser.browser import quickmarks, cookies, cache, adblock +from qutebrowser.browser import quickmarks, cookies, cache, adblock, history from qutebrowser.browser.network import qutescheme, proxy from qutebrowser.mainwindow import mainwindow from qutebrowser.misc import crashdialog, readline, ipc, earlyinit, savemanager @@ -197,6 +197,8 @@ class Application(QApplication): log.init.debug("Initializing cache...") diskcache = cache.DiskCache(self) objreg.register('cache', diskcache) + log.init.debug("Initializing web history...") + history.init() log.init.debug("Initializing main window...") win_id = mainwindow.MainWindow.spawn( False if self._args.nowindow else True) @@ -540,10 +542,10 @@ class Application(QApplication): pages = [] try: - history = objreg.get('command-history')[-5:] + cmd_history = objreg.get('command-history')[-5:] except Exception: log.destroy.exception("Error while getting history: {}") - history = [] + cmd_history = [] try: objects = self.get_all_objects() @@ -562,7 +564,7 @@ class Application(QApplication): log.destroy.exception("Error while preventing shutdown") QApplication.closeAllWindows() self._crashdlg = crashdialog.ExceptionCrashDialog( - self._args.debug, pages, history, exc, objects) + self._args.debug, pages, cmd_history, exc, objects) ret = self._crashdlg.exec_() if ret == QDialog.Accepted: # restore self.restart(shutdown=False, pages=pages) @@ -668,9 +670,9 @@ class Application(QApplication): def report(self): """Report a bug in qutebrowser.""" pages = self._recover_pages() - history = objreg.get('command-history')[-5:] + cmd_history = objreg.get('command-history')[-5:] objects = self.get_all_objects() - self._crashdlg = crashdialog.ReportDialog(pages, history, objects) + self._crashdlg = crashdialog.ReportDialog(pages, cmd_history, objects) self._crashdlg.show() def interrupt(self, signum, _frame): diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py new file mode 100644 index 000000000..91fddff83 --- /dev/null +++ b/qutebrowser/browser/history.py @@ -0,0 +1,114 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014-2015 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Simple history which gets written to disk.""" + +import time +import functools + +from PyQt5.QtCore import pyqtSignal, QStandardPaths +from PyQt5.QtWebKit import QWebHistoryInterface + +from qutebrowser.utils import utils, objreg, standarddir +from qutebrowser.config import config +from qutebrowser.config.parsers import line as lineparser + + +class HistoryEntry: + + """A single entry in the web history. + + Attributes: + atime: The time the page was accessed. + url: The URL which was accessed as string + """ + + def __init__(self, atime, url): + self.atime = atime + self.url = url + + def __repr__(self): + return utils.get_repr(self, constructor=True, atime=self.atime, + url=self.url) + + def __str__(self): + return '{} {}'.format(int(self.atime), self.url) + + @classmethod + def from_str(cls, s): + """Get a history based on a 'TIME URL' string.""" + splitted = s.split(' ') + if len(splitted) != 2: + raise OSError("Invalid history entry '{}'".format(s)) + return cls(*splitted) + + +class WebHistory(QWebHistoryInterface): + + """A QWebHistoryInterface which supports being written to disk.""" + + changed = pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + datadir = standarddir.get(QStandardPaths.DataLocation) + self._linecp = lineparser.LineConfigParser(datadir, 'history', + parent=self) + self._history = [HistoryEntry.from_str(e) for e in self._linecp.data] + objreg.get('save-manager').add_saveable('history', self.save, + self.changed) + + def __repr__(self): + return utils.get_repr(self, length=len(self._history)) + + def save(self): + """Save the history to disk.""" + self._linecp.data = (str(e) for e in self._history) + self._linecp.save() + + def addHistoryEntry(self, url_string): + """Called by WebKit when an URL should be added to the history. + + Args: + url_string: An url as string to add to the history. + """ + if not config.get('general', 'private-browsing'): + entry = HistoryEntry(time.time(), url_string) + self._history.append(entry) + self.historyContains.cache_clear() + self.changed.emit() + + @functools.lru_cache() + def historyContains(self, url_string): + """Called by WebKit to determine if an URL is contained in the history. + + Args: + url_string: The URL (as string) to check for. + + Return: + True if the url is in the history, False otherwise. + """ + return url_string in (entry.url for entry in self._history) + + +def init(): + """Initialize the web history.""" + history = WebHistory() + objreg.register('web-history', history) + QWebHistoryInterface.setDefaultInterface(history)