From a545b919f7f8b4383319c710ad948dca251e76ad Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 2 Jun 2015 23:34:55 +0200 Subject: [PATCH] Do history loading after qutebrowser has started. --- qutebrowser/app.py | 21 +++++++- qutebrowser/browser/history.py | 61 +++++++++++++++++----- qutebrowser/completion/models/instances.py | 5 ++ qutebrowser/completion/models/urlmodel.py | 2 +- 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 2e8f7ea6a..c4ebef460 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -50,7 +50,7 @@ from qutebrowser.mainwindow import mainwindow from qutebrowser.misc import readline, ipc, savemanager, sessions, crashsignal from qutebrowser.misc import utilcmds # pylint: disable=unused-import from qutebrowser.utils import (log, version, message, utils, qtutils, urlutils, - objreg, usertypes, standarddir, error) + objreg, usertypes, standarddir, error, debug) # We import utilcmds to run the cmdutils.register decorators. @@ -148,7 +148,9 @@ def init(args, crash_handler): error.handle_fatal_exc(e, args, "Error while initializing!", pre_text="Error while initializing") sys.exit(usertypes.Exit.err_init) + QTimer.singleShot(0, functools.partial(_process_args, args)) + QTimer.singleShot(10, functools.partial(_init_late_modules, args)) log.init.debug("Initializing eventfilter...") event_filter = EventFilter(qApp) @@ -428,6 +430,23 @@ def _init_modules(args, crash_handler): objreg.get('config').changed.connect(_maybe_hide_mouse_cursor) +def _init_late_modules(args): + """Initialize modules which can be inited after the window is shown.""" + try: + log.init.debug("Reading web history...") + reader = objreg.get('web-history').async_read() + with debug.log_time(log.init, 'Reading history'): + while True: + QApplication.processEvents() + next(reader) + except StopIteration: + pass + except (OSError, UnicodeDecodeError) as e: + error.handle_fatal_exc(e, args, "Error while initializing!", + pre_text="Error while initializing") + sys.exit(usertypes.Exit.err_init) + + class Quitter: """Utility class to quit/restart the QApplication. diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index 2ffbf70c1..72f5aa639 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -67,23 +67,30 @@ class WebHistory(QWebHistoryInterface): _history_dict: An OrderedDict of URLs read from the on-disk history. _new_history: A list of HistoryEntry items of the current session. _saved_count: How many HistoryEntries have been written to disk. + _initial_read_started: Whether async_read was called. + _initial_read_done: Whether async_read has completed. + _temp_history: OrderedDict of temporary history entries before + async_read was called. Signals: - item_about_to_be_added: Emitted before a new HistoryEntry is added. - arg: The new HistoryEntry. + add_completion_item: Emitted before a new HistoryEntry is added. + arg: The new HistoryEntry. item_added: Emitted after a new HistoryEntry is added. arg: The new HistoryEntry. """ - item_about_to_be_added = pyqtSignal(HistoryEntry) + add_completion_item = pyqtSignal(HistoryEntry) item_added = pyqtSignal(HistoryEntry) + async_read_done = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) + self._initial_read_started = False + self._initial_read_done = False self._lineparser = lineparser.AppendLineParser( standarddir.data(), 'history', parent=self) self._history_dict = collections.OrderedDict() - self._read_history() + self._temp_history = collections.OrderedDict() self._new_history = [] self._saved_count = 0 objreg.get('save-manager').add_saveable( @@ -101,12 +108,21 @@ class WebHistory(QWebHistoryInterface): def __len__(self): return len(self._history_dict) - def _read_history(self): + def async_read(self): """Read the initial history.""" - if standarddir.data() is None: + if self._initial_read_started: + log.init.debug("Ignoring async_read() because reading is started.") return + self._initial_read_started = True + + if standarddir.data() is None: + self._initial_read_done = True + self.async_read_done.emit() + return + with self._lineparser.open(): for line in self._lineparser: + yield data = line.rstrip().split(maxsplit=1) if not data: # empty line @@ -128,8 +144,24 @@ class WebHistory(QWebHistoryInterface): # information about previous hits change the items in # old_urls to be lists or change HistoryEntry to have a # list of atimes. - self._history_dict[url] = HistoryEntry(atime, url) - self._history_dict.move_to_end(url) + entry = HistoryEntry(atime, url) + self._add_entry(entry) + + self._initial_read_done = True + self.async_read_done.emit() + + for url, entry in self._temp_history.items(): + entry = HistoryEntry(atime, url) + self._new_history.append(entry) + self._add_entry(entry) + self.add_completion_item.emit(entry) + + def _add_entry(self, entry, target=None): + """Add an entry to self._history_dict or another given OrderedDict.""" + if target is None: + target = self._history_dict + target[entry.url_string] = entry + target.move_to_end(entry.url_string) def get_recent(self): """Get the most recent history entries.""" @@ -151,13 +183,16 @@ class WebHistory(QWebHistoryInterface): """ if not url_string: return - if not config.get('general', 'private-browsing'): - entry = HistoryEntry(time.time(), url_string) - self.item_about_to_be_added.emit(entry) + if config.get('general', 'private-browsing'): + return + entry = HistoryEntry(time.time(), url_string) + if self._initial_read_done: + self.add_completion_item.emit(entry) self._new_history.append(entry) - self._history_dict[url_string] = entry - self._history_dict.move_to_end(url_string) + self._add_entry(entry) self.item_added.emit(entry) + else: + self._add_entry(entry, target=self._temp_history) def historyContains(self, url_string): """Called by WebKit to determine if an URL is contained in the history. diff --git a/qutebrowser/completion/models/instances.py b/qutebrowser/completion/models/instances.py index 85998357f..e39ca1692 100644 --- a/qutebrowser/completion/models/instances.py +++ b/qutebrowser/completion/models/instances.py @@ -165,6 +165,11 @@ def init(): quickmark_manager.changed.connect( functools.partial(update, [usertypes.Completion.quickmark_by_url, usertypes.Completion.quickmark_by_name])) + session_manager = objreg.get('session-manager') session_manager.update_completion.connect( functools.partial(update, [usertypes.Completion.sessions])) + + history = objreg.get('web-history') + history.async_read_done.connect( + functools.partial(update, [usertypes.Completion.url])) diff --git a/qutebrowser/completion/models/urlmodel.py b/qutebrowser/completion/models/urlmodel.py index e8898ec85..1eb7e13d2 100644 --- a/qutebrowser/completion/models/urlmodel.py +++ b/qutebrowser/completion/models/urlmodel.py @@ -54,7 +54,7 @@ class UrlCompletionModel(base.BaseCompletionModel): history = utils.newest_slice(self._history, max_history) for entry in history: self._add_history_entry(entry) - self._history.item_about_to_be_added.connect( + self._history.add_completion_item.connect( self.on_history_item_added) objreg.get('config').changed.connect(self.reformat_timestamps)