Add a hints -> find-implementation setting

This makes it possible to switch to an alternative implementation if
there are weird issues like #1568. Some users might also prefer the
slightly better performance over more accurate hints.
This commit is contained in:
Florian Bruhin 2016-06-09 15:40:22 +02:00
parent 2d54c927e3
commit 035526848e
8 changed files with 51 additions and 15 deletions

View File

@ -35,6 +35,9 @@ Added
- New `hints -> auto-follow-timeout` setting to ignore keypresses after
following a hint when filtering in number mode.
- New `:history-clear` command to clear the entire history
- New `hints -> find-implementation` to select which implementation (JS/Python)
should be used to find hints on a page. The `javascript` implementation is
better, but slower.
Changed
~~~~~~~

View File

@ -186,6 +186,7 @@
|<<hints-auto-follow-timeout,auto-follow-timeout>>|A timeout to inhibit normal-mode key bindings after a successfulauto-follow.
|<<hints-next-regexes,next-regexes>>|A comma-separated list of regexes to use for 'next' links.
|<<hints-prev-regexes,prev-regexes>>|A comma-separated list of regexes to use for 'prev' links.
|<<hints-find-implementation,find-implementation>>|Which implementation to use to find elements to hint.
|==============
.Quick reference for section ``colors''
@ -1637,6 +1638,17 @@ A comma-separated list of regexes to use for 'prev' links.
Default: +pass:[\bprev(ious)?\b,\bback\b,\bolder\b,\b[&lt;←≪]\b,\b(&lt;&lt;|«)\b]+
[[hints-find-implementation]]
=== find-implementation
Which implementation to use to find elements to hint.
Valid values:
* +javascript+: Better but slower
* +python+: Slightly worse but faster
Default: +pass:[javascript]+
== searchengines
Definitions of search engines which can be used via the address bar.
The searchengine named `DEFAULT` is used when `general -> auto-search` is true and something else than a URL was entered to be opened. Other search engines can be used by prepending the search engine name to the search term, e.g. `:open google qutebrowser`. The string `{}` will be replaced by the search term, use `{{` and `}}` for literal `{`/`}` signs.

View File

@ -381,11 +381,12 @@ class HintManager(QObject):
elem: The QWebElement to set the style attributes for.
label: The label QWebElement.
"""
rect = elem.rect_on_view(adjust_zoom=False)
no_js = config.get('hints', 'find-implementation') != 'javascript'
rect = elem.rect_on_view(adjust_zoom=False, no_js=no_js)
left = rect.x()
top = rect.y()
log.hints.vdebug("Drawing label '{!r}' at {}/{} for element '{!r}'"
.format(label, left, top, elem))
log.hints.vdebug("Drawing label '{!r}' at {}/{} for element '{!r}' "
"(no_js: {})".format(label, left, top, elem, no_js))
label.setStyleProperty('left', '{}px !important'.format(left))
label.setStyleProperty('top', '{}px !important'.format(top))

View File

@ -173,14 +173,9 @@ class WebElementWrapper(collections.abc.MutableMapping):
"""
return is_visible(self._elem, mainframe)
def rect_on_view(self, *, adjust_zoom=True):
"""Get the geometry of the element relative to the webview.
Args:
adjust_zoom: Whether to adjust the element position based on the
current zoom level.
"""
return rect_on_view(self._elem, adjust_zoom=adjust_zoom)
def rect_on_view(self, **kwargs):
"""Get the geometry of the element relative to the webview."""
return rect_on_view(self._elem, **kwargs)
def is_writable(self):
"""Check whether an element is writable."""
@ -368,7 +363,7 @@ def focus_elem(frame):
return WebElementWrapper(elem)
def rect_on_view(elem, *, elem_geometry=None, adjust_zoom=True):
def rect_on_view(elem, *, elem_geometry=None, adjust_zoom=True, no_js=False):
"""Get the geometry of the element relative to the webview.
We need this as a standalone function (as opposed to a WebElementWrapper
@ -391,13 +386,14 @@ def rect_on_view(elem, *, elem_geometry=None, adjust_zoom=True):
want to avoid doing it twice.
adjust_zoom: Whether to adjust the element position based on the
current zoom level.
no_js: Fall back to the Python implementation
"""
if elem.isNull():
raise IsNullError("Got called on a null element!")
# First try getting the element rect via JS, as that's usually more
# accurate
if elem_geometry is None:
if elem_geometry is None and not no_js:
rects = elem.evaluateJavaScript("this.getClientRects()")
text = utils.compact_text(elem.toOuterXml(), 500)
log.hints.vdebug("Client rectangles of element '{}': {}".format(text,

View File

@ -930,6 +930,14 @@ def data(readonly=False):
r'\b(<<|«)\b'),
"A comma-separated list of regexes to use for 'prev' links."),
('find-implementation',
SettingValue(typ.String(
valid_values=typ.ValidValues(
('javascript', "Better but slower"),
('python', "Slightly worse but faster"),
)), 'javascript'),
"Which implementation to use to find elements to hint."),
readonly=readonly
)),

View File

@ -232,4 +232,3 @@ Feature: Using hints
And I press the key "2"
And I wait for "Leaving mode KeyMode.hint (reason: all filtered)" in the log
Then no crash should happen

View File

@ -38,7 +38,9 @@ def collect_tests():
@pytest.mark.parametrize('test_name', collect_tests())
@pytest.mark.parametrize('zoom_text_only', [True, False])
@pytest.mark.parametrize('zoom_level', [100, 66, 33])
def test_hints(test_name, zoom_text_only, zoom_level, quteproc):
@pytest.mark.parametrize('find_implementation', ['javascript', 'python'])
def test_hints(test_name, zoom_text_only, zoom_level, find_implementation,
quteproc):
file_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'data', 'hints', 'html', test_name)
url_path = 'data/hints/html/{}'.format(test_name)
@ -69,6 +71,7 @@ def test_hints(test_name, zoom_text_only, zoom_level, quteproc):
# setup
quteproc.send_cmd(':set ui zoom-text-only {}'.format(zoom_text_only))
quteproc.set_setting('hints', 'find-implementation', find_implementation)
quteproc.send_cmd(':zoom {}'.format(zoom_level))
# follow hint
quteproc.send_cmd(':hint links normal')

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Different hint implementations</title>
</head>
<body>
<p>When setting hints -> find-implementation to python, the label for the wrapped hint should be drawn at the wrong position.</p>
<div style="width: 20em;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis <a href="/data/hello.txt">nostrud exercitation</a> ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</body>
</html>