From fd678ff864190b68a0a7a426ddfd7f60cc588f57 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 1 May 2014 15:27:32 +0200 Subject: [PATCH] Make hints work --- qutebrowser/browser/curcommand.py | 20 ++++++++++++++++ qutebrowser/browser/hints.py | 28 ++++++++++++++--------- qutebrowser/config/_conftypes.py | 38 +++++++++++++++++++++++++++++++ qutebrowser/config/configdata.py | 15 ++++++++++++ qutebrowser/utils/webelem.py | 4 ++-- 5 files changed, 92 insertions(+), 13 deletions(-) diff --git a/qutebrowser/browser/curcommand.py b/qutebrowser/browser/curcommand.py index bb744db81..a0027aa94 100644 --- a/qutebrowser/browser/curcommand.py +++ b/qutebrowser/browser/curcommand.py @@ -222,6 +222,26 @@ class CurCommandDispatcher(QObject): """Fire a completed hint.""" self._tabs.currentWidget().hintmanager.fire(keystr) + @cmdutils.register(instance='mainwindow.tabs.cur') + def prev_page(self): + """Click on a "previous" link.""" + widget = self._tabs.currentWidget() + frame = widget.page_.currentFrame() + if frame is None: + message.error("No frame focused!") + return + widget.hintmanager.click_prevnext(frame, prev=True) + + @cmdutils.register(instance='mainwindow.tabs.cur') + def next_page(self): + """Click on a "next" link.""" + widget = self._tabs.currentWidget() + frame = widget.page_.currentFrame() + if frame is None: + message.error("No frame focused!") + return + widget.hintmanager.click_prevnext(frame, prev=False) + @pyqtSlot(str, int) def search(self, text, flags): """Search for text in the current page. diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 37319bdf0..716d9d565 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -207,19 +207,24 @@ class HintManager(QObject): css, string)) return doc.lastChild() - def _click(self, elem): + def _click(self, elem, target=None, frame=None): """Click an element. Args: elem: The QWebElement to click. + target_override: Target which overrides self._target """ - if self._target == 'rapid': + if target is not None: + pass + elif self._target == 'rapid': target = 'bgtab' else: target = self._target + if frame is None: + frame = self._frame self.set_open_target.emit(target) point = elem.geometry().topLeft() - scrollpos = self._frame.scrollPosition() + scrollpos = frame.scrollPosition() logging.debug("Clicking on \"{}\" at {}/{} - {}/{}".format( elem.toPlainText(), point.x(), point.y(), scrollpos.x(), scrollpos.y())) @@ -281,22 +286,23 @@ class HintManager(QObject): def click_prevnext(self, frame, prev=False): """Click a "previous"/"next" element on the page.""" # First check for - self.target='normal' elems = frame.findAllElements(webelem.SELECTORS['prevnext_rel']) rel_values = ['prev', 'previous'] if prev else ['next'] for e in elems: if e.attribute('rel') in rel_values: - self.click(e) + self._click(e, 'normal', frame) return # Then check for regular links elems = frame.findAllElements(webelem.SELECTORS['prevnext']) option = 'prev-regexes' if prev else 'next-regexes' - for regex in config.get('hints', option): - for e in elems: - if regex.match(e.toPlainText()): - self.click(e) - return - message.error("No prev/forward links found!") + if elems: + for regex in config.get('hints', option): + for e in elems: + if regex.match(e.toPlainText()): + self._click(e, 'normal', frame) + return + message.error("No {} links found!".format("prev" if prev + else "forward")) def start(self, frame, baseurl, mode='all', target='normal'): diff --git a/qutebrowser/config/_conftypes.py b/qutebrowser/config/_conftypes.py index d4c458591..cc6c36b00 100644 --- a/qutebrowser/config/_conftypes.py +++ b/qutebrowser/config/_conftypes.py @@ -17,7 +17,9 @@ """Setting options used for qutebrowser.""" +import re import shlex +from sre_constants import error as RegexError from PyQt5.QtGui import QColor @@ -511,6 +513,42 @@ class KeyBindingName(BaseType): pass +class Regex(BaseType): + + """A regular expression.""" + + def __init__(self, flags=0): + self.flags = flags + + def validate(self, value): + try: + re.compile(value, self.flags) + except RegexError as e: + raise ValidationError(value, "must be a valid regex - " + str(e)) + + def transform(self, value): + return re.compile(value, self.flags) + + +class RegexList(List): + + """A list of regexes.""" + + def __init__(self, flags=0): + self.flags=flags + + def transform(self, value): + vals = super().transform(value) + return [re.compile(pattern, self.flags) for pattern in vals] + + def validate(self, value): + try: + self.transform(value) + except RegexError as e: + raise ValidationError(value, "must be a list valid regexes - " + + str(e)) + + class AutoSearch(BaseType): """Whether to start a search when something else than an URL is entered.""" diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index b5af4337f..bbcee95c5 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -24,6 +24,7 @@ SECTION_DESC: A dictionary with descriptions for sections. DATA: The config defaults, an OrderedDict of sections. """ +import re from collections import OrderedDict from qutebrowser.config._value import SettingValue @@ -397,6 +398,18 @@ DATA = OrderedDict([ ('auto-follow', SettingValue(types.Bool(), 'true'), "Whether to auto-follow a hint if there's only one left."), + + ('next-regexes', + SettingValue(types.RegexList(flags=re.IGNORECASE), + r'\bnext\b,\bmore\b,\bnewer\b,^>$$,^(>>|»|→|≫)$$,' + r'^(>|»|→|≫),(>|»|→|≫)$$'), + "A comma-separated list of regexes to use for 'next' links."), + + ('prev-regexes', + SettingValue(types.RegexList(flags=re.IGNORECASE), + r'\bprev(ious)\b,\bback\b,\bolder\b,^<$$,^(<<|«|←|≪)$$,' + r'^(<|«|←|≪),(<|«|←|≪)$$'), + "A comma-separated list of regexes to use for 'prev' links."), )), ('searchengines', sect.ValueList( @@ -456,6 +469,8 @@ DATA = OrderedDict([ ('PP', 'tabpaste sel'), ('-', 'zoomout'), ('+', 'zoomin'), + ('[[', 'prev_page'), + (']]', 'next_page'), ('', 'enter_mode passthrough'), ('', 'quit'), ('', 'undo'), diff --git a/qutebrowser/utils/webelem.py b/qutebrowser/utils/webelem.py index 63faf8d5a..5a0bad7cc 100644 --- a/qutebrowser/utils/webelem.py +++ b/qutebrowser/utils/webelem.py @@ -36,8 +36,8 @@ SELECTORS = { 'input[type=tel], input[type=number], ' 'input[type=password], input[type=search], textarea'), 'url': '[src], [href]', - 'prevnext_rel': 'link [role=link]', - 'prevnext': 'a button [role=button]', + 'prevnext_rel': 'link, [role=link]', + 'prevnext': 'a, button, [role=button]', } SELECTORS['editable_focused'] = ', '.join(