From 0f8296d384bf8cf0bf6674483c30ed3f3513c0a2 Mon Sep 17 00:00:00 2001 From: Olmo Kramer Date: Thu, 22 Mar 2018 23:45:16 +0100 Subject: [PATCH 1/8] Add hints.selectors setting --- doc/help/settings.asciidoc | 68 ++++++++++++++++++++ qutebrowser/browser/hints.py | 22 +++++-- qutebrowser/browser/navigate.py | 5 +- qutebrowser/browser/webelem.py | 27 +------- qutebrowser/config/configdata.yml | 54 ++++++++++++++++ tests/unit/browser/webkit/test_webkitelem.py | 68 +++++++++----------- 6 files changed, 174 insertions(+), 70 deletions(-) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 75e684ffc..b545282ea 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -203,6 +203,7 @@ |<>|Comma-separated list of regular expressions to use for 'next' links. |<>|Comma-separated list of regular expressions to use for 'prev' links. |<>|Scatter hint key chains (like Vimium) or not (like dwb). +|<>|CSS selectors used to determine which elements on a page should have hints. |<>|Make characters in hint strings uppercase. |<>|Maximum time (in minutes) between two history items for them to be considered being from the same browsing session. |<>|Allow Escape to quit the crash reporter. @@ -2479,6 +2480,73 @@ Type: <> Default: +pass:[true]+ +[[hints.selectors]] +=== hints.selectors +CSS selectors used to determine which elements on a page should have hints. + +This setting supports URL patterns. + +Type: <> + +Default: + +- +pass:[all]+: + +* +pass:[a]+ +* +pass:[area]+ +* +pass:[textarea]+ +* +pass:[select]+ +* +pass:[input:not([type="hidden"])]+ +* +pass:[button]+ +* +pass:[frame]+ +* +pass:[iframe]+ +* +pass:[img]+ +* +pass:[link]+ +* +pass:[summary]+ +* +pass:[[onclick]]+ +* +pass:[[onmousedown]]+ +* +pass:[[role="link"]]+ +* +pass:[[role="option"]]+ +* +pass:[[role="button"]]+ +* +pass:[[ng-click]]+ +* +pass:[[ngClick]]+ +* +pass:[[data-ng-click]]+ +* +pass:[[x-ng-click]]+ +- +pass:[images]+: + +* +pass:[img]+ +- +pass:[inputs]+: + +* +pass:[input[type="text"]]+ +* +pass:[input[type="date"]]+ +* +pass:[input[type="datetime-local"]]+ +* +pass:[input[type="email"]]+ +* +pass:[input[type="month"]]+ +* +pass:[input[type="number"]]+ +* +pass:[input[type="password"]]+ +* +pass:[input[type="search"]]+ +* +pass:[input[type="tel"]]+ +* +pass:[input[type="time"]]+ +* +pass:[input[type="url"]]+ +* +pass:[input[type="week"]]+ +* +pass:[input:not([type])]+ +* +pass:[textarea]+ +- +pass:[links]+: + +* +pass:[a[href]]+ +* +pass:[area[href]]+ +* +pass:[link[href]]+ +* +pass:[[role="link"][href]]+ +- +pass:[media]+: + +* +pass:[audio]+ +* +pass:[img]+ +* +pass:[video]+ +- +pass:[urls]+: + +* +pass:[[src]]+ +* +pass:[[href]]+ + [[hints.uppercase]] === hints.uppercase Make characters in hint strings uppercase. diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 6e5f4d7f4..27d869023 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -637,9 +637,8 @@ class HintManager(QObject): star_args_optional=True, maxsplit=2) @cmdutils.argument('win_id', win_id=True) def start(self, # pylint: disable=keyword-arg-before-vararg - group=webelem.Group.all, target=Target.normal, - *args, win_id, mode=None, add_history=False, rapid=False, - first=False): + group='all', target=Target.normal, *args, win_id, mode=None, + add_history=False, rapid=False, first=False): """Start hinting. Args: @@ -741,10 +740,25 @@ class HintManager(QObject): raise cmdexc.CommandError("No URL set for this page yet!") self._context.args = args self._context.group = group - selector = webelem.SELECTORS[self._context.group] + selector = self._get_selector() self._context.tab.elements.find_css(selector, self._start_cb, only_visible=True) + def _get_selector(self): + """Get the CSS selectors for this url and hinting group.""" + url = self._context.baseurl + group = self._context.group + + selectors = config.instance.get('hints.selectors', url) + if group not in selectors: + selectors = config.val.hints.selectors + + if group not in selectors: + raise cmdexc.CommandError("Undefined hinting group " + "'{}'!".format(group)) + + return ','.join(selectors[group]) + def current_mode(self): """Return the currently active hinting mode (or None otherwise).""" if self._context is None: diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py index 257ce6fe0..dbe2b5ed9 100644 --- a/qutebrowser/browser/navigate.py +++ b/qutebrowser/browser/navigate.py @@ -21,7 +21,6 @@ import posixpath -from qutebrowser.browser import webelem from qutebrowser.config import config from qutebrowser.utils import objreg, urlutils, log, message, qtutils from qutebrowser.mainwindow import mainwindow @@ -147,5 +146,5 @@ def prevnext(*, browsertab, win_id, baseurl, prev=False, else: browsertab.openurl(url) - browsertab.elements.find_css(webelem.SELECTORS[webelem.Group.links], - _prevnext_cb) + link_selector = 'a[href], area[href], link[href], [role=link][href]' + browsertab.elements.find_css(link_selector, _prevnext_cb) diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index 1d719738b..91bfd4d6e 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -17,14 +17,8 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -"""Generic web element related code. +"""Generic web element related code.""" -Module attributes: - Group: Enum for different kinds of groups. - SELECTORS: CSS selectors for different groups of elements. -""" - -import enum import collections.abc from PyQt5.QtCore import QUrl, Qt, QEvent, QTimer @@ -36,25 +30,6 @@ from qutebrowser.mainwindow import mainwindow from qutebrowser.utils import log, usertypes, utils, qtutils, objreg -Group = enum.Enum('Group', ['all', 'links', 'images', 'url', 'inputs']) - - -SELECTORS = { - Group.all: ('a, area, textarea, select, input:not([type=hidden]), button, ' - 'frame, iframe, link, summary, [onclick], [onmousedown], ' - '[role=link], [role=option], [role=button], img, ' - # Angular 1 selectors - '[ng-click], [ngClick], [data-ng-click], [x-ng-click]'), - Group.links: 'a[href], area[href], link[href], [role=link][href]', - Group.images: 'img', - Group.url: '[src], [href]', - Group.inputs: ('input[type=text], input[type=email], input[type=url], ' - 'input[type=tel], input[type=number], ' - 'input[type=password], input[type=search], ' - 'input:not([type]), textarea'), -} - - class Error(Exception): """Base class for WebElement errors.""" diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 2698c34b1..73184be82 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1037,6 +1037,60 @@ hints.scatter: Ignored for number hints. +hints.selectors: + default: + all: + - 'a' + - 'area' + - 'textarea' + - 'select' + - 'input:not([type="hidden"])' + - 'button' + - 'frame' + - 'iframe' + - 'img' + - 'link' + - 'summary' + - '[onclick]' + - '[onmousedown]' + - '[role="link"]' + - '[role="option"]' + - '[role="button"]' + - '[ng-click]' + - '[ngClick]' + - '[data-ng-click]' + - '[x-ng-click]' + links: + - 'a[href]' + - 'area[href]' + - 'link[href]' + - '[role="link"][href]' + images: + - 'img' + urls: + - '[src]' + - '[href]' + inputs: + - 'input[type="text"]' + - 'input[type="email"]' + - 'input[type="url"]' + - 'input[type="tel"]' + - 'input[type="number"]' + - 'input[type="password"]' + - 'input[type="search"]' + - 'input:not([type])' + - 'textarea' + type: + name: Dict + keytype: String + valtype: + name: List + none_ok: true + valtype: String + supports_pattern: true + desc: CSS selectors used to determine which elements on a page should have + hints. + hints.uppercase: default: false type: Bool diff --git a/tests/unit/browser/webkit/test_webkitelem.py b/tests/unit/browser/webkit/test_webkitelem.py index df3de6310..eb06a3bca 100644 --- a/tests/unit/browser/webkit/test_webkitelem.py +++ b/tests/unit/browser/webkit/test_webkitelem.py @@ -29,7 +29,7 @@ import pytest from PyQt5.QtCore import QRect, QPoint, QUrl QWebElement = pytest.importorskip('PyQt5.QtWebKit').QWebElement -from qutebrowser.browser import webelem, browsertab +from qutebrowser.browser import browsertab from qutebrowser.browser.webkit import webkitelem from qutebrowser.misc import objects from qutebrowser.utils import usertypes @@ -146,53 +146,46 @@ class SelectionAndFilterTests: TESTS = [ ('', []), ('', []), - ('', [webelem.Group.url]), - ('', [webelem.Group.url]), + ('', ['urls']), + ('', ['urls']), - ('', [webelem.Group.all]), - ('', [webelem.Group.all, webelem.Group.links, - webelem.Group.url]), - ('', [webelem.Group.all, - webelem.Group.links, - webelem.Group.url]), + ('', ['all']), + ('', ['all', 'links', 'urls']), + ('', ['all', 'links', 'urls']), - ('', [webelem.Group.all]), - ('', [webelem.Group.all, webelem.Group.links, - webelem.Group.url]), + ('', ['all']), + ('', ['all', 'links', 'urls']), - ('', [webelem.Group.all]), - ('', [webelem.Group.all, webelem.Group.links, - webelem.Group.url]), + ('', ['all']), + ('', ['all', 'links', 'urls']), - ('