Skip to content
Permalink
Browse files

Move most :navigate code to browser.navigate

  • Loading branch information
The-Compiler committed Aug 5, 2016
1 parent 68595e1 commit 778ccad39f1962924a3755c67f82c54b9eee787b
Showing with 170 additions and 133 deletions.
  1. +24 −56 qutebrowser/browser/commands.py
  2. +0 −77 qutebrowser/browser/hints.py
  3. +146 −0 qutebrowser/browser/navigate.py
@@ -22,7 +22,6 @@
import os
import os.path
import shlex
import posixpath
import functools

from PyQt5.QtWidgets import QApplication, QTabBar
@@ -40,7 +39,7 @@

from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.config import config, configexc
from qutebrowser.browser import urlmarks, browsertab, inspector
from qutebrowser.browser import urlmarks, browsertab, inspector, navigate
from qutebrowser.browser.webkit import webelem, downloads, mhtml
from qutebrowser.keyinput import modeman
from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils,
@@ -440,40 +439,6 @@ def forward(self, tab=False, bg=False, window=False, count=1):
"""
self._back_forward(tab, bg, window, count, forward=True)

def _navigate_incdec(self, url, incdec, tab, background, window):
"""Helper method for :navigate when `where' is increment/decrement.
Args:
url: The current url.
incdec: Either 'increment' or 'decrement'.
tab: Whether to open the link in a new tab.
background: Open the link in a new background tab.
window: Open the link in a new window.
"""
segments = set(config.get('general', 'url-incdec-segments'))
try:
new_url = urlutils.incdec_number(url, incdec, segments=segments)
except urlutils.IncDecError as error:
raise cmdexc.CommandError(error.msg)

self._open(new_url, tab, background, window)

def _navigate_up(self, url, tab, background, window):
"""Helper method for :navigate when `where' is up.
Args:
url: The current url.
tab: Whether to open the link in a new tab.
background: Open the link in a new background tab.
window: Open the link in a new window.
"""
path = url.path()
if not path or path == '/':
raise cmdexc.CommandError("Can't go up!")
new_path = posixpath.join(path, posixpath.pardir)
url.setPath(new_path)
self._open(url, tab, background, window)

@cmdutils.register(instance='command-dispatcher', scope='window',
backend=usertypes.Backend.QtWebKit)
@cmdutils.argument('where', choices=['prev', 'next', 'up', 'increment',
@@ -506,26 +471,29 @@ def navigate(self, where: str, tab=False, bg=False, window=False):
widget = self._current_widget()
url = self._current_url().adjusted(QUrl.RemoveFragment)

if where in ['prev', 'next']:
# FIXME:qtwebengine have a proper API for this
if widget.backend == usertypes.Backend.QtWebEngine:
raise cmdexc.CommandError(":navigate prev/next is not "
"supported yet with QtWebEngine")

hintmanager = objreg.get('hintmanager', scope='tab', tab='current')
if where == 'prev':
hintmanager.follow_prevnext(widget, url, prev=True, tab=tab,
background=bg, window=window)
elif where == 'next':
hintmanager.follow_prevnext(widget, url, prev=False, tab=tab,
background=bg, window=window)
elif where == 'up':
self._navigate_up(url, tab, bg, window)
elif where in ['decrement', 'increment']:
self._navigate_incdec(url, where, tab, bg, window)
else: # pragma: no cover
raise ValueError("Got called with invalid value {} for "
"`where'.".format(where))
handlers = {
'prev': functools.partial(navigate.prevnext, prev=True),
'next': functools.partial(navigate.prevnext, prev=False),
'up': navigate.path_up,
'decrement': functools.partial(navigate.incdec,
inc_or_dec='decrement'),
'increment': functools.partial(navigate.incdec,
inc_or_dec='increment'),
}

try:
if where in ['prev', 'next']:
handler = handlers[where]
handler(browsertab=widget, win_id=self._win_id, baseurl=url,
tab=tab, background=bg, window=window)
elif where in ['up', 'increment', 'decrement']:
new_url = handlers[where](url)
self._open(new_url, tab, bg, window)
else: # pragma: no cover
raise ValueError("Got called with invalid value {} for "
"`where'.".format(where))
except navigate.Error as e:
raise cmdexc.CommandError(e)

@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@@ -630,83 +630,6 @@ def _filter_matches(self, filterstr, elemstr):
# Do multi-word matching
return all(word in elemstr for word in filterstr.split())

def _find_prevnext(self, prev, elems):
"""Find a prev/next element in the given list of elements."""
# First check for <link rel="prev(ious)|next">
rel_values = ('prev', 'previous') if prev else ('next')
for e in elems:
if e.tag_name() != 'link' or 'rel' not in e:
continue
if e['rel'] in rel_values:
log.hints.debug("Found '{}' with rel={}".format(
e.debug_text(), e['rel']))
return e

# Then check for regular links/buttons.
filterfunc = webelem.FILTERS[webelem.Group.prevnext]
elems = [e for e in elems if e.tag_name() != 'link' and filterfunc(e)]
option = 'prev-regexes' if prev else 'next-regexes'
if not elems:
return None
for regex in config.get('hints', option):
log.hints.vdebug("== Checking regex '{}'.".format(regex.pattern))
for e in elems:
text = str(e)
if not text:
continue
if regex.search(text):
log.hints.debug("Regex '{}' matched on '{}'.".format(
regex.pattern, text))
return e
else:
log.hints.vdebug("No match on '{}'!".format(text))
return None

def follow_prevnext(self, browsertab, baseurl, prev=False, tab=False,
background=False, window=False):
"""Click a "previous"/"next" element on the page.
Args:
browsertab: The WebKitTab/WebEngineTab of the page.
baseurl: The base URL of the current tab.
prev: True to open a "previous" link, False to open a "next" link.
tab: True to open in a new tab, False for the current tab.
background: True to open in a background tab.
window: True to open in a new window, False for the current one.
"""
def _follow_prevnext_cb(elems):
elem = self._find_prevnext(prev, elems)
word = 'prev' if prev else 'forward'

if elem is None:
message.error(self._win_id, "No {} links found!".format(word))
return
url = _resolve_url(elem, baseurl)
if url is None:
message.error(self._win_id, "No {} links found!".format(word))
return
qtutils.ensure_valid(url)

if window:
from qutebrowser.mainwindow import mainwindow
new_window = mainwindow.MainWindow()
new_window.show()
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=new_window.win_id)
tabbed_browser.tabopen(url, background=False)
elif tab:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=self._win_id)
tabbed_browser.tabopen(url, background=background)
else:
browsertab = objreg.get('tab', scope='tab',
window=self._win_id, tab=self._tab_id)
browsertab.openurl(url)

selector = ', '.join([webelem.SELECTORS[webelem.Group.links],
webelem.SELECTORS[webelem.Group.prevnext]])
browsertab.find_all_elements(selector, _follow_prevnext_cb)

def _start_cb(self, elems):
"""Initialize the elements and labels based on the context set."""
filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True)
@@ -0,0 +1,146 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:

# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.

"""Implementation of :navigate"""

import posixpath

from qutebrowser.browser.webkit import webelem
from qutebrowser.config import config
from qutebrowser.utils import (usertypes, objreg, urlutils, log, message,
qtutils)


class Error(Exception):

"""Raised when the navigation can't be done."""


def incdec(url, inc_or_dec):
"""Helper method for :navigate when `where' is increment/decrement.
Args:
url: The current url.
inc_or_dec: Either 'increment' or 'decrement'.
tab: Whether to open the link in a new tab.
background: Open the link in a new background tab.
window: Open the link in a new window.
"""
segments = set(config.get('general', 'url-incdec-segments'))
try:
new_url = urlutils.incdec_number(url, inc_or_dec, segments=segments)
except urlutils.IncDecError as error:
raise Error(error.msg)
return new_url


def path_up(url):
"""Helper method for :navigate when `where' is up.
Args:
url: The current url.
"""
path = url.path()
if not path or path == '/':
raise Error("Can't go up!")
new_path = posixpath.join(path, posixpath.pardir)
url.setPath(new_path)
return url


def _find_prevnext(prev, elems):
"""Find a prev/next element in the given list of elements."""
# First check for <link rel="prev(ious)|next">
rel_values = ('prev', 'previous') if prev else ('next')
for e in elems:
if e.tag_name() != 'link' or 'rel' not in e:
continue
if e['rel'] in rel_values:
log.hints.debug("Found '{}' with rel={}".format(
e.debug_text(), e['rel']))
return e

# Then check for regular links/buttons.
filterfunc = webelem.FILTERS[webelem.Group.prevnext]
elems = [e for e in elems if e.tag_name() != 'link' and filterfunc(e)]
option = 'prev-regexes' if prev else 'next-regexes'
if not elems:
return None
for regex in config.get('hints', option):
log.hints.vdebug("== Checking regex '{}'.".format(regex.pattern))
for e in elems:
text = str(e)
if not text:
continue
if regex.search(text):
log.hints.debug("Regex '{}' matched on '{}'.".format(
regex.pattern, text))
return e
else:
log.hints.vdebug("No match on '{}'!".format(text))
return None


def prevnext(*, browsertab, win_id, baseurl, prev=False,
tab=False, background=False, window=False):
"""Click a "previous"/"next" element on the page.
Args:
browsertab: The WebKitTab/WebEngineTab of the page.
baseurl: The base URL of the current tab.
prev: True to open a "previous" link, False to open a "next" link.
tab: True to open in a new tab, False for the current tab.
background: True to open in a background tab.
window: True to open in a new window, False for the current one.
"""
# FIXME:qtwebengine have a proper API for this
if browsertab.backend == usertypes.Backend.QtWebEngine:
raise Error(":navigate prev/next is not supported yet with "
"QtWebEngine")

def _prevnext_cb(elems):
elem = _find_prevnext(prev, elems)
word = 'prev' if prev else 'forward'

if elem is None:
message.error(win_id, "No {} links found!".format(word))
return
url = elem.resolve_url(baseurl)
if url is None:
message.error(win_id, "No {} links found!".format(word))
return
qtutils.ensure_valid(url)

if window:
from qutebrowser.mainwindow import mainwindow
new_window = mainwindow.MainWindow()
new_window.show()
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=new_window.win_id)
tabbed_browser.tabopen(url, background=False)
elif tab:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
tabbed_browser.tabopen(url, background=background)
else:
browsertab.openurl(url)

selector = ', '.join([webelem.SELECTORS[webelem.Group.links],
webelem.SELECTORS[webelem.Group.prevnext]])
browsertab.find_all_elements(selector, _prevnext_cb)

0 comments on commit 778ccad

Please sign in to comment.