Use SQL completion for the open command.

Now that history, bookmark, and quickmark storage are SQL-backed, use
a sql completion model to serve url completions.
This commit is contained in:
Ryan Roden-Corrent 2017-02-05 19:34:14 -05:00
parent 6e1ea89ca1
commit acea0d3c67
2 changed files with 12 additions and 173 deletions

View File

@ -19,180 +19,19 @@
"""Function to return the url completion model for the `open` command."""
import datetime
from PyQt5.QtCore import pyqtSlot, Qt
from qutebrowser.utils import objreg, utils, qtutils, log
from qutebrowser.completion.models import base
from qutebrowser.config import config
_URL_COLUMN = 0
_TEXT_COLUMN = 1
_TIME_COLUMN = 2
_model = None
_history_cat = None
_quickmark_cat = None
_bookmark_cat = None
def _delete_url(completion):
index = completion.currentIndex()
qtutils.ensure_valid(index)
category = index.parent()
index = category.child(index.row(), _URL_COLUMN)
qtutils.ensure_valid(category)
if category.data() == 'Bookmarks':
bookmark_manager = objreg.get('bookmark-manager')
bookmark_manager.delete(index.data())
elif category.data() == 'Quickmarks':
quickmark_manager = objreg.get('quickmark-manager')
sibling = index.sibling(index.row(), _TEXT_COLUMN)
qtutils.ensure_valid(sibling)
name = sibling.data()
quickmark_manager.delete(name)
def _remove_oldest_history():
"""Remove the oldest history entry."""
_history_cat.removeRow(0)
def _add_history_entry(entry):
"""Add a new history entry to the completion."""
_model.new_item(_history_cat, entry.url.toDisplayString(),
entry.title, _fmt_atime(entry.atime),
sort=int(entry.atime), userdata=entry.url)
max_history = config.get('completion', 'web-history-max-items')
if max_history != -1 and _history_cat.rowCount() > max_history:
_remove_oldest_history()
@config.change_filter('completion', 'timestamp-format')
def _reformat_timestamps():
"""Reformat the timestamps if the config option was changed."""
for i in range(_history_cat.rowCount()):
url_item = _history_cat.child(i, _URL_COLUMN)
atime_item = _history_cat.child(i, _TIME_COLUMN)
atime = url_item.data(base.Role.sort)
atime_item.setText(_fmt_atime(atime))
@pyqtSlot(object)
def _on_history_item_added(entry):
"""Slot called when a new history item was added."""
for i in range(_history_cat.rowCount()):
url_item = _history_cat.child(i, _URL_COLUMN)
atime_item = _history_cat.child(i, _TIME_COLUMN)
title_item = _history_cat.child(i, _TEXT_COLUMN)
if url_item.data(base.Role.userdata) == entry.url:
atime_item.setText(_fmt_atime(entry.atime))
title_item.setText(entry.title)
url_item.setData(int(entry.atime), base.Role.sort)
break
else:
_add_history_entry(entry)
@pyqtSlot()
def _on_history_cleared():
_history_cat.removeRows(0, _history_cat.rowCount())
def _remove_item(data, category, column):
"""Helper function for on_quickmark_removed and on_bookmark_removed.
Args:
data: The item to search for.
category: The category to search in.
column: The column to use for matching.
"""
for i in range(category.rowCount()):
item = category.child(i, column)
if item.data(Qt.DisplayRole) == data:
category.removeRow(i)
break
@pyqtSlot(str)
def _on_quickmark_removed(name):
"""Called when a quickmark has been removed by the user.
Args:
name: The name of the quickmark which has been removed.
"""
_remove_item(name, _quickmark_cat, _TEXT_COLUMN)
@pyqtSlot(str)
def _on_bookmark_removed(urltext):
"""Called when a bookmark has been removed by the user.
Args:
urltext: The url of the bookmark which has been removed.
"""
_remove_item(urltext, _bookmark_cat, _URL_COLUMN)
def _fmt_atime(atime):
"""Format an atime to a human-readable string."""
fmt = config.get('completion', 'timestamp-format')
if fmt is None:
return ''
try:
dt = datetime.datetime.fromtimestamp(atime)
except (ValueError, OSError, OverflowError):
# Different errors which can occur for too large values...
log.misc.error("Got invalid timestamp {}!".format(atime))
return '(invalid)'
else:
return dt.strftime(fmt)
def _init():
global _model, _quickmark_cat, _bookmark_cat, _history_cat
_model = base.CompletionModel(column_widths=(40, 50, 10),
dumb_sort=Qt.DescendingOrder,
delete_cur_item=_delete_url,
columns_to_filter=[_URL_COLUMN,
_TEXT_COLUMN])
_quickmark_cat = _model.new_category("Quickmarks")
_bookmark_cat = _model.new_category("Bookmarks")
_history_cat = _model.new_category("History")
quickmark_manager = objreg.get('quickmark-manager')
quickmarks = quickmark_manager.marks.items()
for qm_name, qm_url in quickmarks:
_model.new_item(_quickmark_cat, qm_url, qm_name)
quickmark_manager.added.connect(
lambda name, url: _model.new_item(_quickmark_cat, url, name))
quickmark_manager.removed.connect(_on_quickmark_removed)
bookmark_manager = objreg.get('bookmark-manager')
bookmarks = bookmark_manager.marks.items()
for bm_url, bm_title in bookmarks:
_model.new_item(_bookmark_cat, bm_url, bm_title)
bookmark_manager.added.connect(
lambda name, url: _model.new_item(_bookmark_cat, url, name))
bookmark_manager.removed.connect(_on_bookmark_removed)
history = objreg.get('web-history')
max_history = config.get('completion', 'web-history-max-items')
for entry in utils.newest_slice(history, max_history):
if not entry.redirect:
_add_history_entry(entry)
history.add_completion_item.connect(_on_history_item_added)
history.cleared.connect(_on_history_cleared)
objreg.get('config').changed.connect(_reformat_timestamps)
from qutebrowser.completion.models import sqlmodel
def url():
"""A _model which combines bookmarks, quickmarks and web history URLs.
"""A model which combines bookmarks, quickmarks and web history URLs.
Used for the `open` command.
"""
if not _model:
_init()
return _model
urlcol = 0
textcol = 1
model = sqlmodel.SqlCompletionModel(column_widths=(40, 50, 10),
columns_to_filter=[urlcol, textcol])
model.new_category('History')
model.new_category('Quickmarks')
model.new_category('Bookmarks')
return model

View File

@ -27,7 +27,7 @@ from hypothesis import strategies
from PyQt5.QtCore import QUrl
from qutebrowser.browser import history
from qutebrowser.utils import objreg, urlutils
from qutebrowser.utils import objreg, urlutils, usertypes
from qutebrowser.misc import sql