diff --git a/.gitignore b/.gitignore
index 9efceef63..ceafd9946 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@ TODO
/scripts/testbrowser/cpp/webengine/.qmake.stash
/scripts/dev/pylint_checkers/qute_pylint.egg-info
/misc/file_version_info.txt
+/doc/extapi/_build
diff --git a/doc/extapi/_static/.gitkeep b/doc/extapi/_static/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/doc/extapi/_templates/.gitkeep b/doc/extapi/_templates/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/doc/extapi/api.rst b/doc/extapi/api.rst
new file mode 100644
index 000000000..b63db57c3
--- /dev/null
+++ b/doc/extapi/api.rst
@@ -0,0 +1,48 @@
+API modules
+===========
+
+cmdutils module
+---------------
+
+.. automodule:: qutebrowser.api.cmdutils
+ :members:
+ :imported-members:
+
+apitypes module
+---------------
+
+.. automodule:: qutebrowser.api.apitypes
+ :members:
+ :imported-members:
+
+config module
+-------------
+
+.. automodule:: qutebrowser.api.config
+ :members:
+
+downloads module
+----------------
+
+.. automodule:: qutebrowser.api.downloads
+ :members:
+
+hook module
+-----------
+
+.. automodule:: qutebrowser.api.hook
+ :members:
+
+interceptor module
+------------------
+
+.. automodule:: qutebrowser.api.interceptor
+ :members:
+ :imported-members:
+
+message module
+--------------
+
+.. automodule:: qutebrowser.api.message
+ :members:
+ :imported-members:
diff --git a/doc/extapi/conf.py b/doc/extapi/conf.py
new file mode 100644
index 000000000..4cc5c6803
--- /dev/null
+++ b/doc/extapi/conf.py
@@ -0,0 +1,179 @@
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'qutebrowser extensions'
+copyright = '2018, Florian Bruhin'
+author = 'Florian Bruhin'
+
+# The short X.Y version
+version = ''
+# The full version, including alpha/beta/rc tags
+release = ''
+
+
+# -- General configuration ---------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.napoleon',
+]
+autodoc_member_order = 'bysource'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself. Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'qutebrowserextensionsdoc'
+
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'qutebrowserextensions.tex', 'qutebrowser extensions Documentation',
+ 'Florian Bruhin', 'manual'),
+]
+
+
+# -- Options for manual page output ------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'qutebrowserextensions', 'qutebrowser extensions Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output ----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'qutebrowserextensions', 'qutebrowser extensions Documentation',
+ author, 'qutebrowserextensions', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+
+# -- Options for Epub output -------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+
+# -- Extension configuration -------------------------------------------------
diff --git a/doc/extapi/index.rst b/doc/extapi/index.rst
new file mode 100644
index 000000000..d181c2ccd
--- /dev/null
+++ b/doc/extapi/index.rst
@@ -0,0 +1,22 @@
+.. qutebrowser extensions documentation master file, created by
+ sphinx-quickstart on Tue Dec 11 18:59:44 2018.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to qutebrowser extensions's documentation!
+==================================================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ api
+ tab
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/extapi/tab.rst b/doc/extapi/tab.rst
new file mode 100644
index 000000000..57a14ac6e
--- /dev/null
+++ b/doc/extapi/tab.rst
@@ -0,0 +1,44 @@
+Tab API
+=======
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractTab()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractAction()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractPrinting()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractSearch()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractZoom()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractCaret()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractScroller()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractHistory()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractElements()
+ :members:
+
+.. autoclass:: qutebrowser.browser.browsertab.AbstractAudio()
+ :members:
+
+Web element API
+===============
+
+.. autoclass:: qutebrowser.browser.webelem.AbstractWebElement
+ :members:
+
+.. autoclass:: qutebrowser.browser.webelem.Error
+ :members:
+
+.. autoclass:: qutebrowser.browser.webelem.OrphanedError
+ :members:
diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt
new file mode 100644
index 000000000..c0801a48e
--- /dev/null
+++ b/misc/requirements/requirements-sphinx.txt
@@ -0,0 +1,21 @@
+# This file is automatically generated by scripts/dev/recompile_requirements.py
+
+alabaster==0.7.12
+Babel==2.6.0
+certifi==2018.11.29
+chardet==3.0.4
+docutils==0.14
+idna==2.8
+imagesize==1.1.0
+Jinja2==2.10
+MarkupSafe==1.1.0
+packaging==18.0
+Pygments==2.3.0
+pyparsing==2.3.0
+pytz==2018.7
+requests==2.21.0
+six==1.12.0
+snowballstemmer==1.2.1
+Sphinx==1.8.2
+sphinxcontrib-websupport==1.1.0
+urllib3==1.24.1
diff --git a/misc/requirements/requirements-sphinx.txt-raw b/misc/requirements/requirements-sphinx.txt-raw
new file mode 100644
index 000000000..6966869c7
--- /dev/null
+++ b/misc/requirements/requirements-sphinx.txt-raw
@@ -0,0 +1 @@
+sphinx
diff --git a/qutebrowser/api/cmdutils.py b/qutebrowser/api/cmdutils.py
index 093244727..f6a6f6da9 100644
--- a/qutebrowser/api/cmdutils.py
+++ b/qutebrowser/api/cmdutils.py
@@ -17,7 +17,38 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
-"""Utilities for command handlers."""
+"""
+qutebrowser has the concept of functions which are exposed to the user as
+commands.
+
+Creating a new command is straightforward::
+
+ from qutebrowser.api import cmdutils
+
+ @cmdutils.register(...)
+ def foo():
+ ...
+
+The commands arguments are automatically deduced by inspecting your function.
+
+The types of the function arguments are inferred based on their default values,
+e.g., an argument `foo=True` will be converted to a flag `-f`/`--foo` in
+qutebrowser's commandline.
+
+The type can be overridden using Python's function annotations::
+
+ @cmdutils.register(...)
+ def foo(bar: int, baz=True):
+ ...
+
+Possible values:
+
+- A callable (``int``, ``float``, etc.): Gets called to validate/convert the value.
+- A python enum type: All members of the enum are possible values.
+- A ``typing.Union`` of multiple types above: Any of these types are valid
+ values, e.g., ``typing.Union[str, int]``.
+"""
+
import inspect
import typing
@@ -33,15 +64,17 @@ class CommandError(cmdexc.Error):
"""Raised when a command encounters an error while running.
If your command handler encounters an error and cannot continue, raise this
- exception with an appropriate error message:
+ exception with an appropriate error message::
raise cmdexc.CommandError("Message")
The message will then be shown in the qutebrowser status bar.
- Note that you should only raise this exception while a command handler is
- run. Raising it at another point causes qutebrowser to crash due to an
- unhandled exception.
+ .. note::
+
+ You should only raise this exception while a command handler is run.
+ Raising it at another point causes qutebrowser to crash due to an
+ unhandled exception.
"""
@@ -76,13 +109,7 @@ def check_exclusive(flags: typing.Iterable[bool],
class register: # noqa: N801,N806 pylint: disable=invalid-name
- """Decorator to register a new command handler.
-
- Attributes:
- _instance: The object from the object registry to be used as "self".
- _name: The name (as string) or names (as list) of the command.
- _kwargs: The arguments to pass to Command.
- """
+ """Decorator to register a new command handler."""
def __init__(self, *,
instance: str = None,
@@ -95,8 +122,11 @@ class register: # noqa: N801,N806 pylint: disable=invalid-name
Args:
See class attributes.
"""
+ # The object from the object registry to be used as "self".
self._instance = instance
+ # The name (as string) or names (as list) of the command.
self._name = name
+ # The arguments to pass to Command.
self._kwargs = kwargs
def __call__(self, func: typing.Callable) -> typing.Callable:
@@ -127,16 +157,47 @@ class register: # noqa: N801,N806 pylint: disable=invalid-name
class argument: # noqa: N801,N806 pylint: disable=invalid-name
- """Decorator to customize an argument for @cmdutils.register.
+ """Decorator to customize an argument.
- Attributes:
- _argname: The name of the argument to handle.
- _kwargs: Keyword arguments, valid ArgInfo members
+ You can customize how an argument is handled using the ``@cmdutils.argument``
+ decorator *after* ``@cmdutils.register``. This can, for example, be used to
+ customize the flag an argument should get::
+
+ @cmdutils.register(...)
+ @cmdutils.argument('bar', flag='c')
+ def foo(bar):
+ ...
+
+ For a ``str`` argument, you can restrict the allowed strings using ``choices``::
+
+ @cmdutils.register(...)
+ @cmdutils.argument('bar', choices=['val1', 'val2'])
+ def foo(bar: str):
+ ...
+
+ For ``typing.Union`` types, the given ``choices`` are only checked if other types
+ (like ``int``) don't match.
+
+ The following arguments are supported for ``@cmdutils.argument``:
+
+ - ``flag``: Customize the short flag (``-x``) the argument will get.
+ - ``value``: Tell qutebrowser to fill the argument with special values:
+
+ * ``value=cmdutils.Value.count``: The ``count`` given by the user to the command.
+ * ``value=cmdutils.Value.win_id``: The window ID of the current window.
+ * ``value=cmdutils.Value.cur_tab``: The tab object which is currently focused.
+
+ - ``completion``: A completion function to use when completing arguments for
+ the given command.
+ - ``choices``: The allowed string choices for the argument.
+
+ The name of an argument will always be the parameter name, with any trailing
+ underscores stripped and underscores replaced by dashes.
"""
def __init__(self, argname: str, **kwargs: typing.Any) -> None:
- self._argname = argname
- self._kwargs = kwargs
+ self._argname = argname # The name of the argument to handle.
+ self._kwargs = kwargs # Valid ArgInfo members.
def __call__(self, func: typing.Callable) -> typing.Callable:
funcname = func.__name__
diff --git a/qutebrowser/api/config.py b/qutebrowser/api/config.py
index 4a5d73936..0c633e54d 100644
--- a/qutebrowser/api/config.py
+++ b/qutebrowser/api/config.py
@@ -25,6 +25,16 @@ from PyQt5.QtCore import QUrl
from qutebrowser.config import config
+#: Simplified access to config values using attribute acccess.
+#: For example, to access the ``content.javascript.enabled`` setting,
+#: you can do::
+#:
+#: if config.val.content.javascript.enabled:
+#: ...
+#:
+#: This also supports setting configuration values::
+#:
+#: config.val.content.javascript.enabled = False
val = typing.cast('config.ConfigContainer', None)
diff --git a/qutebrowser/api/downloads.py b/qutebrowser/api/downloads.py
index 82c68d0bd..a2a37d931 100644
--- a/qutebrowser/api/downloads.py
+++ b/qutebrowser/api/downloads.py
@@ -52,6 +52,21 @@ def download_temp(url: QUrl) -> TempDownload:
"""Download the given URL into a file object.
The download is not saved to disk.
+
+ Returns a ``TempDownload`` object, which triggers a ``finished`` signal
+ when the download has finished::
+
+ dl = downloads.download_temp(QUrl("https://www.example.com/"))
+ dl.finished.connect(functools.partial(on_download_finished, dl))
+
+ After the download has finished, its ``successful`` attribute can be
+ checked to make sure it finished successfully. If so, its contents can be
+ read by accessing the ``fileobj`` attribute::
+
+ def on_download_finished(download: downloads.TempDownload) -> None:
+ if download.successful:
+ print(download.fileobj.read())
+ download.fileobj.close()
"""
fobj = io.BytesIO()
fobj.name = 'temporary: ' + url.host()
diff --git a/qutebrowser/api/hook.py b/qutebrowser/api/hook.py
index 3f06121da..84e103cbd 100644
--- a/qutebrowser/api/hook.py
+++ b/qutebrowser/api/hook.py
@@ -36,7 +36,17 @@ def _add_module_info(func: typing.Callable) -> loader.ModuleInfo:
class init:
- """Decorator to mark a function to run when initializing."""
+ """Decorator to mark a function to run when initializing.
+
+ The decorated function gets called with a
+ :class:`qutebrowser.api.apitypes.InitContext` as argument.
+
+ Example::
+
+ @hook.init()
+ def init(_context):
+ message.info("Extension initialized.")
+ """
def __call__(self, func: typing.Callable) -> typing.Callable:
info = _add_module_info(func)
@@ -48,7 +58,30 @@ class init:
class config_changed:
- """Decorator to get notified about changed configs."""
+ """Decorator to get notified about changed configs.
+
+ By default, the decorated function is called when any change in the config
+ occurs::
+
+ @hook.config_changed()
+ def on_config_changed():
+ ...
+
+ When an option name is passed, it's only called when the given option was
+ changed::
+
+ @hook.config_changed('content.javascript.enabled')
+ def on_config_changed():
+ ...
+
+ Alternatively, a part of an option name can be specified. In the following
+ snippet, ``on_config_changed`` gets called when either
+ ``bindings.commands`` or ``bindings.key_mappings`` have changed::
+
+ @hook.config_changed('bindings')
+ def on_config_changed():
+ ...
+ """
def __init__(self, option_filter: str = None) -> None:
self._filter = option_filter
diff --git a/qutebrowser/api/interceptor.py b/qutebrowser/api/interceptor.py
index a40635fca..634ae1409 100644
--- a/qutebrowser/api/interceptor.py
+++ b/qutebrowser/api/interceptor.py
@@ -27,7 +27,13 @@ from qutebrowser.extensions.interceptors import Request
def register(interceptor: interceptors.InterceptorType) -> None:
"""Register a request interceptor.
- Whenever a request happens, the interceptor gets called with a Request
- object.
+ Whenever a request happens, the interceptor gets called with a
+ :class:`Request` object.
+
+ Example::
+
+ def intercept(request: interceptor.Request) -> None:
+ if request.request_url.host() == 'badhost.example.com':
+ request.block()
"""
interceptors.register(interceptor)
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 3bd4c55c3..029394657 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -141,14 +141,11 @@ class TabData:
class AbstractAction:
- """Attribute of AbstractTab for Qt WebActions.
-
- Class attributes (overridden by subclasses):
- action_class: The class actions are defined on (QWeb{Engine,}Page)
- action_base: The type of the actions (QWeb{Engine,}Page.WebAction)
- """
+ """Attribute ``action`` of AbstractTab for Qt WebActions."""
+ # The class actions are defined on (QWeb{Engine,}Page)
action_class = None # type: type
+ # The type of the actions (QWeb{Engine,}Page.WebAction)
action_base = None # type: type
def __init__(self, tab: 'AbstractTab') -> None:
@@ -200,7 +197,7 @@ class AbstractAction:
class AbstractPrinting:
- """Attribute of AbstractTab for printing the page."""
+ """Attribute ``printing`` of AbstractTab for printing the page."""
def __init__(self, tab: 'AbstractTab') -> None:
self._widget = None
@@ -271,7 +268,7 @@ class AbstractPrinting:
class AbstractSearch(QObject):
- """Attribute of AbstractTab for doing searches.
+ """Attribute ``search`` of AbstractTab for doing searches.
Attributes:
text: The last thing this view was searched for.
@@ -279,15 +276,14 @@ class AbstractSearch(QObject):
this view.
_flags: The flags of the last search (needs to be set by subclasses).
_widget: The underlying WebView widget.
-
- Signals:
- finished: Emitted when a search was finished.
- arg: True if the text was found, False otherwise.
- cleared: Emitted when an existing search was cleared.
"""
+ #: Signal emitted when a search was finished
+ #: (True if the text was found, False otherwise)
finished = pyqtSignal(bool)
+ #: Signal emitted when an existing search was cleared.
cleared = pyqtSignal()
+
_Callback = typing.Callable[[bool], None]
def __init__(self, tab: 'AbstractTab', parent: QWidget = None):
@@ -350,17 +346,13 @@ class AbstractSearch(QObject):
class AbstractZoom(QObject):
- """Attribute of AbstractTab for controlling zoom.
-
- Attributes:
- _neighborlist: A NeighborList with the zoom levels.
- _default_zoom_changed: Whether the zoom was changed from the default.
- """
+ """Attribute ``zoom`` of AbstractTab for controlling zoom."""
def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None:
super().__init__(parent)
self._tab = tab
self._widget = None
+ # Whether zoom was changed from the default.
self._default_zoom_changed = False
self._init_neighborlist()
config.instance.changed.connect(self._on_config_changed)
@@ -375,7 +367,9 @@ class AbstractZoom(QObject):
self._init_neighborlist()
def _init_neighborlist(self) -> None:
- """Initialize self._neighborlist."""
+ """Initialize self._neighborlist.
+
+ It is a NeighborList with the zoom levels."""
levels = config.val.zoom.levels
self._neighborlist = usertypes.NeighborList(
levels, mode=usertypes.NeighborList.Modes.edge)
@@ -427,15 +421,12 @@ class AbstractZoom(QObject):
class AbstractCaret(QObject):
- """Attribute of AbstractTab for caret browsing.
-
- Signals:
- selection_toggled: Emitted when the selection was toggled.
- arg: Whether the selection is now active.
- follow_selected_done: Emitted when a follow_selection action is done.
- """
+ """Attribute ``caret`` of AbstractTab for caret browsing."""
+ #: Signal emitted when the selection was toggled.
+ #: (argument - whether the selection is now active)
selection_toggled = pyqtSignal(bool)
+ #: Emitted when a ``follow_selection`` action is done.
follow_selected_done = pyqtSignal()
def __init__(self,
@@ -522,16 +513,12 @@ class AbstractCaret(QObject):
class AbstractScroller(QObject):
- """Attribute of AbstractTab to manage scroll position.
-
- Signals:
- perc_changed: The scroll position changed.
- before_jump_requested:
- Emitted by other code when the user requested a jump.
- Used to set the special ' mark so the user can return.
- """
+ """Attribute ``scroller`` of AbstractTab to manage scroll position."""
+ #: Signal emitted when the scroll position changed (int, int)
perc_changed = pyqtSignal(int, int)
+ #: Signal emitted before the user requested a jump.
+ #: Used to set the special ' mark so the user can return.
before_jump_requested = pyqtSignal()
def __init__(self, tab: 'AbstractTab', parent: QWidget = None):
@@ -833,42 +820,46 @@ class AbstractTabPrivate:
class AbstractTab(QWidget):
- """An adapter for QWebView/QWebEngineView representing a single tab.
-
- Signals:
- See related Qt signals.
-
- new_tab_requested: Emitted when a new tab should be opened with the
- given URL.
- load_status_changed: The loading status changed
- fullscreen_requested: Fullscreen display was requested by the page.
- arg: True if fullscreen should be turned on,
- False if it should be turned off.
- renderer_process_terminated: Emitted when the underlying renderer
- process terminated.
- arg 0: A TerminationStatus member.
- arg 1: The exit code.
- before_load_started: Emitted before we tell Qt to open a URL.
- """
+ """An adapter for QWebView/QWebEngineView representing a single tab."""
+ #: Signal emitted when a website requests to close this tab.
window_close_requested = pyqtSignal()
+ #: Signal emitted when a link is hovered (the hover text)
link_hovered = pyqtSignal(str)
+ #: Signal emitted when a page started loading
load_started = pyqtSignal()
+ #: Signal emitted when a page is loading (progress percentage)
load_progress = pyqtSignal(int)
+ #: Signal emitted when a page finished loading (success as bool)
load_finished = pyqtSignal(bool)
+ #: Signal emitted when a page's favicon changed (icon as QIcon)
icon_changed = pyqtSignal(QIcon)
+ #: Signal emitted when a page's title changed (new title as str)
title_changed = pyqtSignal(str)
- load_status_changed = pyqtSignal(usertypes.LoadStatus)
+ #: Signal emitted when a new tab should be opened (url as QUrl)
new_tab_requested = pyqtSignal(QUrl)
+ #: Signal emitted when a page's URL changed (url as QUrl)
url_changed = pyqtSignal(QUrl)
- shutting_down = pyqtSignal()
+ #: Signal emitted when a tab's content size changed
+ #: (new size as QSizeF)
contents_size_changed = pyqtSignal(QSizeF)
- # url, requested url, title
- history_item_triggered = pyqtSignal(QUrl, QUrl, str)
+ #: Signal emitted when a page requested full-screen (bool)
fullscreen_requested = pyqtSignal(bool)
- renderer_process_terminated = pyqtSignal(TerminationStatus, int)
+ #: Signal emitted before load starts (URL as QUrl)
before_load_started = pyqtSignal(QUrl)
+ # Signal emitted when a page's load status changed
+ # (argument: usertypes.LoadStatus)
+ load_status_changed = pyqtSignal(usertypes.LoadStatus)
+ # Signal emitted before shutting down
+ shutting_down = pyqtSignal()
+ # Signal emitted when a history item should be added
+ history_item_triggered = pyqtSignal(QUrl, QUrl, str)
+ # Signal emitted when the underlying renderer process terminated.
+ # arg 0: A TerminationStatus member.
+ # arg 1: The exit code.
+ renderer_process_terminated = pyqtSignal(TerminationStatus, int)
+
def __init__(self, *, win_id: int, private: bool,
parent: QWidget = None) -> None:
self.is_private = private
diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py
index a22facfbd..c00f247f6 100644
--- a/qutebrowser/browser/webelem.py
+++ b/qutebrowser/browser/webelem.py
@@ -141,20 +141,9 @@ class AbstractWebElement(collections.abc.MutableMapping):
def rect_on_view(self, *, elem_geometry=None, no_js=False):
"""Get the geometry of the element relative to the webview.
- Uses the getClientRects() JavaScript method to obtain the collection of
- rectangles containing the element and returns the first rectangle which
- is large enough (larger than 1px times 1px). If all rectangles returned
- by getClientRects() are too small, falls back to elem.rect_on_view().
-
- Skipping of small rectangles is due to elements containing other
- elements with "display:block" style, see
- https://github.com/qutebrowser/qutebrowser/issues/1298
-
Args:
elem_geometry: The geometry of the element, or None.
- Calling QWebElement::geometry is rather expensive so
- we want to avoid doing it twice.
- no_js: Fall back to the Python implementation
+ no_js: Fall back to the Python implementation.
"""
raise NotImplementedError
diff --git a/qutebrowser/extensions/interceptors.py b/qutebrowser/extensions/interceptors.py
index 4a3ac17d4..269c82ab8 100644
--- a/qutebrowser/extensions/interceptors.py
+++ b/qutebrowser/extensions/interceptors.py
@@ -34,8 +34,12 @@ class Request:
"""A request which can be intercepted/blocked."""
+ #: The URL of the page being shown.
first_party_url = attr.ib() # type: QUrl
+
+ #: The URL of the file being requested.
request_url = attr.ib() # type: QUrl
+
is_blocked = attr.ib(False) # type: bool
def block(self) -> None:
diff --git a/qutebrowser/utils/message.py b/qutebrowser/utils/message.py
index b496273f8..6731721aa 100644
--- a/qutebrowser/utils/message.py
+++ b/qutebrowser/utils/message.py
@@ -42,12 +42,12 @@ def _log_stack(typ: str, stack: str) -> None:
def error(message: str, *, stack: str = None, replace: bool = False) -> None:
- """Convenience function to display an error message in the statusbar.
+ """Display an error message.
Args:
- message: The message to show
- stack: The stack trace to show.
- replace: Replace existing messages with replace=True
+ message: The message to show.
+ stack: The stack trace to show (if any).
+ replace: Replace existing messages which are still being shown.
"""
if stack is None:
stack = ''.join(traceback.format_stack())
@@ -60,11 +60,11 @@ def error(message: str, *, stack: str = None, replace: bool = False) -> None:
def warning(message: str, *, replace: bool = False) -> None:
- """Convenience function to display a warning message in the statusbar.
+ """Display a warning message.
Args:
- message: The message to show
- replace: Replace existing messages with replace=True
+ message: The message to show.
+ replace: Replace existing messages which are still being shown.
"""
_log_stack('warning', ''.join(traceback.format_stack()))
log.message.warning(message)
@@ -72,11 +72,11 @@ def warning(message: str, *, replace: bool = False) -> None:
def info(message: str, *, replace: bool = False) -> None:
- """Convenience function to display an info message in the statusbar.
+ """Display an info message.
Args:
- message: The message to show
- replace: Replace existing messages with replace=True
+ message: The message to show.
+ replace: Replace existing messages which are still being shown.
"""
log.message.info(message)
global_bridge.show(usertypes.MessageLevel.info, message, replace)
diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py
index c948df48f..84b7e7f9b 100644
--- a/qutebrowser/utils/usertypes.py
+++ b/qutebrowser/utils/usertypes.py
@@ -210,15 +210,33 @@ PromptMode = enum.Enum('PromptMode', ['yesno', 'text', 'user_pwd', 'alert',
'download'])
-# Where to open a clicked link.
-ClickTarget = enum.Enum('ClickTarget', ['normal', 'tab', 'tab_bg', 'window',
- 'hover'])
+class ClickTarget(enum.Enum):
+
+ """How to open a clicked link."""
+
+ normal = 0 #: Open the link in the current tab
+ tab = 1 #: Open the link in a new foreground tab
+ tab_bg = 2 #: Open the link in a new background tab
+ window = 3 #: Open the link in a new window
+ hover = 4 #: Only hover over the link
-# Key input modes
-KeyMode = enum.Enum('KeyMode', ['normal', 'hint', 'command', 'yesno', 'prompt',
- 'insert', 'passthrough', 'caret', 'set_mark',
- 'jump_mark', 'record_macro', 'run_macro'])
+class KeyMode(enum.Enum):
+
+ """Key input modes."""
+
+ normal = 1 #: Normal mode (no mode was entered)
+ hint = 2 #: Hint mode (showing labels for links)
+ command = 3 #: Command mode (after pressing the colon key)
+ yesno = 4 #: Yes/No prompts
+ prompt = 5 #: Text prompts
+ insert = 6 #: Insert mode (passing through most keys)
+ passthrough = 7 #: Passthrough mode (passing through all keys)
+ caret = 8 #: Caret mode (moving cursor with keys)
+ set_mark = 9
+ jump_mark = 10
+ record_macro = 11
+ run_macro = 12
class Exit(enum.IntEnum):
@@ -241,8 +259,14 @@ LoadStatus = enum.Enum('LoadStatus', ['none', 'success', 'success_https',
Backend = enum.Enum('Backend', ['QtWebKit', 'QtWebEngine'])
-# JS world for QtWebEngine
-JsWorld = enum.Enum('JsWorld', ['main', 'application', 'user', 'jseval'])
+class JsWorld(enum.Enum):
+
+ """World/context to run JavaScript code in."""
+
+ main = 1 #: Same world as the web page's JavaScript.
+ application = 2 #: Application world, used by qutebrowser internally.
+ user = 3 #: User world, currently not used.
+ jseval = 4 #: World used for the jseval-command.
# Log level of a JS message. This needs to match up with the keys allowed for
diff --git a/tox.ini b/tox.ini
index 8a4232aaa..bc44df987 100644
--- a/tox.ini
+++ b/tox.ini
@@ -199,3 +199,14 @@ deps =
-r{toxinidir}/misc/requirements/requirements-mypy.txt
commands =
{envpython} -m mypy qutebrowser {posargs}
+
+[testenv:sphinx]
+basepython = {env:PYTHON:python3}
+passenv =
+usedevelop = true
+deps =
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/misc/requirements/requirements-pyqt.txt
+ -r{toxinidir}/misc/requirements/requirements-sphinx.txt
+commands =
+ {envpython} -m sphinx -jauto -W --color {posargs} doc/extapi/ doc/extapi/_build/