This commit is contained in:
Florian Bruhin 2014-04-17 17:44:27 +02:00
parent 975d83b50e
commit 39f580d9f1
30 changed files with 239 additions and 151 deletions

View File

@ -168,7 +168,11 @@ class QuteBrowser(QApplication):
return parser.parse_args() return parser.parse_args()
def _initlog(self): def _initlog(self):
"""Initialisation of the logging output.""" """Initialisation of the logging output.
Raise:
ValueError if there was an invalid loglevel.
"""
loglevel = 'debug' if self._args.debug else self._args.loglevel loglevel = 'debug' if self._args.debug else self._args.loglevel
numeric_level = getattr(logging, loglevel.upper(), None) numeric_level = getattr(logging, loglevel.upper(), None)
if not isinstance(numeric_level, int): if not isinstance(numeric_level, int):
@ -190,7 +194,7 @@ class QuteBrowser(QApplication):
def _init_cmds(self): def _init_cmds(self):
"""Initialisation of the qutebrowser commands. """Initialisation of the qutebrowser commands.
Registers all commands, connects its signals, and sets up keyparser. Registers all commands and connects their signals.
""" """
for key, cmd in sorted(cmdutils.cmd_dict.items()): for key, cmd in sorted(cmdutils.cmd_dict.items()):
cmd.signal.connect(self.command_handler) cmd.signal.connect(self.command_handler)

View File

@ -37,26 +37,22 @@ class CurCommandDispatcher(QObject):
cmdutils.register() decorators are run, currentWidget() will return None. cmdutils.register() decorators are run, currentWidget() will return None.
Attributes: Attributes:
tabs: The TabbedBrowser object. _tabs: The TabbedBrowser object.
Signals: Signals:
temp_message: Connected to TabbedBrowser signal. temp_message: Connected to TabbedBrowser signal.
""" """
# FIXME maybe subclassing would be more clean?
temp_message = pyqtSignal(str) temp_message = pyqtSignal(str)
def __init__(self, parent): def __init__(self, parent):
"""Constructor. """Constructor.
Uses setattr to get some methods from parent.
Args: Args:
parent: The TabbedBrowser for this dispatcher. parent: The TabbedBrowser for this dispatcher.
""" """
super().__init__(parent) super().__init__(parent)
self.tabs = parent self._tabs = parent
def _scroll_percent(self, perc=None, count=None, orientation=None): def _scroll_percent(self, perc=None, count=None, orientation=None):
"""Inner logic for scroll_percent_(x|y). """Inner logic for scroll_percent_(x|y).
@ -72,7 +68,7 @@ class CurCommandDispatcher(QObject):
perc = int(count) perc = int(count)
else: else:
perc = float(perc) perc = float(perc)
frame = self.tabs.currentWidget().page_.mainFrame() frame = self._tabs.currentWidget().page_.mainFrame()
m = frame.scrollBarMaximum(orientation) m = frame.scrollBarMaximum(orientation)
if m == 0: if m == 0:
return return
@ -88,12 +84,12 @@ class CurCommandDispatcher(QObject):
url: The URL to open. url: The URL to open.
count: The tab index to open the URL in, or None. count: The tab index to open the URL in, or None.
""" """
tab = self.tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is None: if tab is None:
if count is None: if count is None:
# We want to open an URL in the current tab, but none exists # We want to open an URL in the current tab, but none exists
# yet. # yet.
self.tabs.tabopen(url) self._tabs.tabopen(url)
else: else:
# Explicit count with a tab that doesn't exist. # Explicit count with a tab that doesn't exist.
return return
@ -109,7 +105,7 @@ class CurCommandDispatcher(QObject):
Args: Args:
count: The tab index to reload, or None. count: The tab index to reload, or None.
""" """
tab = self.tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is not None: if tab is not None:
tab.reload() tab.reload()
@ -122,7 +118,7 @@ class CurCommandDispatcher(QObject):
Args: Args:
count: The tab index to stop, or None. count: The tab index to stop, or None.
""" """
tab = self.tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is not None: if tab is not None:
tab.stop() tab.stop()
@ -136,7 +132,7 @@ class CurCommandDispatcher(QObject):
count: The tab index to print, or None. count: The tab index to print, or None.
""" """
# FIXME that does not what I expect # FIXME that does not what I expect
tab = self.tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is not None: if tab is not None:
preview = QPrintPreviewDialog(self) preview = QPrintPreviewDialog(self)
preview.paintRequested.connect(tab.print) preview.paintRequested.connect(tab.print)
@ -153,7 +149,7 @@ class CurCommandDispatcher(QObject):
""" """
# FIXME display warning if beginning of history # FIXME display warning if beginning of history
for _ in range(count): for _ in range(count):
self.tabs.currentWidget().back() self._tabs.currentWidget().back()
@cmdutils.register(instance='mainwindow.tabs.cur') @cmdutils.register(instance='mainwindow.tabs.cur')
def forward(self, count=1): def forward(self, count=1):
@ -166,7 +162,7 @@ class CurCommandDispatcher(QObject):
""" """
# FIXME display warning if end of history # FIXME display warning if end of history
for _ in range(count): for _ in range(count):
self.tabs.currentWidget().forward() self._tabs.currentWidget().forward()
@pyqtSlot(str, int) @pyqtSlot(str, int)
def search(self, text, flags): def search(self, text, flags):
@ -176,7 +172,7 @@ class CurCommandDispatcher(QObject):
text: The text to search for. text: The text to search for.
flags: The QWebPage::FindFlags. flags: The QWebPage::FindFlags.
""" """
self.tabs.currentWidget().findText(text, flags) self._tabs.currentWidget().findText(text, flags)
@cmdutils.register(instance='mainwindow.tabs.cur', hide=True) @cmdutils.register(instance='mainwindow.tabs.cur', hide=True)
def scroll(self, dx, dy, count=1): def scroll(self, dx, dy, count=1):
@ -191,7 +187,7 @@ class CurCommandDispatcher(QObject):
""" """
dx = int(count) * float(dx) dx = int(count) * float(dx)
dy = int(count) * float(dy) dy = int(count) * float(dy)
self.tabs.currentWidget().page_.mainFrame().scroll(dx, dy) self._tabs.currentWidget().page_.mainFrame().scroll(dx, dy)
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x', @cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
hide=True) hide=True)
@ -229,7 +225,7 @@ class CurCommandDispatcher(QObject):
count: multiplier count: multiplier
""" """
# FIXME this might not work with HTML frames # FIXME this might not work with HTML frames
page = self.tabs.currentWidget().page_ page = self._tabs.currentWidget().page_
size = page.viewportSize() size = page.viewportSize()
page.mainFrame().scroll(int(count) * float(mx) * size.width(), page.mainFrame().scroll(int(count) * float(mx) * size.width(),
int(count) * float(my) * size.height()) int(count) * float(my) * size.height())
@ -247,7 +243,7 @@ class CurCommandDispatcher(QObject):
temp_message to display a temporary message. temp_message to display a temporary message.
""" """
clip = QApplication.clipboard() clip = QApplication.clipboard()
url = urlutils.urlstring(self.tabs.currentWidget().url()) url = urlutils.urlstring(self._tabs.currentWidget().url())
mode = QClipboard.Selection if sel else QClipboard.Clipboard mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(url, mode) clip.setText(url, mode)
self.temp_message.emit('URL yanked to {}'.format( self.temp_message.emit('URL yanked to {}'.format(
@ -266,7 +262,7 @@ class CurCommandDispatcher(QObject):
temp_message to display a temporary message. temp_message to display a temporary message.
""" """
clip = QApplication.clipboard() clip = QApplication.clipboard()
title = self.tabs.tabText(self.tabs.currentIndex()) title = self._tabs.tabText(self._tabs.currentIndex())
mode = QClipboard.Selection if sel else QClipboard.Clipboard mode = QClipboard.Selection if sel else QClipboard.Clipboard
clip.setText(title, mode) clip.setText(title, mode)
self.temp_message.emit('Title yanked to {}'.format( self.temp_message.emit('Title yanked to {}'.format(
@ -279,7 +275,7 @@ class CurCommandDispatcher(QObject):
Args: Args:
count: How many steps to take. count: How many steps to take.
""" """
tab = self.tabs.currentWidget() tab = self._tabs.currentWidget()
tab.zoom(count) tab.zoom(count)
@cmdutils.register(instance='mainwindow.tabs.cur', name='zoomout') @cmdutils.register(instance='mainwindow.tabs.cur', name='zoomout')
@ -289,5 +285,5 @@ class CurCommandDispatcher(QObject):
Args: Args:
count: How many steps to take. count: How many steps to take.
""" """
tab = self.tabs.currentWidget() tab = self._tabs.currentWidget()
tab.zoom(-count) tab.zoom(-count)

View File

@ -91,7 +91,7 @@ class SignalFilter(QObject):
if self._tabs.currentWidget() == sender: if self._tabs.currentWidget() == sender:
if log_signal: if log_signal:
logging.debug(' emitting') logging.debug(' emitting')
return signal.emit(*args) signal.emit(*args)
else: else:
if log_signal: if log_signal:
logging.debug(' ignoring') logging.debug(' ignoring')

View File

@ -117,6 +117,6 @@ class Command(QObject):
self.signal.emit((self.instance, self.handler.__name__, None, self.signal.emit((self.instance, self.handler.__name__, None,
args)) args))
elif count is not None and self.count: elif count is not None and self.count:
return self.handler(*args, count=count) self.handler(*args, count=count)
else: else:
return self.handler(*args) self.handler(*args)

View File

@ -15,7 +15,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Parse keypresses/keychains in the main window.""" """Parse keypresses/keychains in the main window.
Module attributes:
STARTCHARS: Possible chars for starting a commandline input.
"""
import re import re
import logging import logging
@ -27,7 +31,6 @@ import qutebrowser.config.config as config
from qutebrowser.commands.parsers import (CommandParser, ArgumentCountError, from qutebrowser.commands.parsers import (CommandParser, ArgumentCountError,
NoSuchCommandError) NoSuchCommandError)
# Possible chars for starting a commandline input
STARTCHARS = ":/?" STARTCHARS = ":/?"
@ -35,6 +38,12 @@ class KeyParser(QObject):
"""Parser for vim-like key sequences. """Parser for vim-like key sequences.
Class Attributes:
MATCH_PARTIAL: Constant for a partial match (no keychain matched yet,
but it's still possible in the future.
MATCH_DEFINITIVE: Constant for a full match (keychain matches exactly).
MATCH_NONE: Constant for no match (no more matches possible).
Attributes: Attributes:
commandparser: Commandparser instance. commandparser: Commandparser instance.
_keystring: The currently entered key sequence _keystring: The currently entered key sequence
@ -241,7 +250,7 @@ class KeyParser(QObject):
"""Read the configuration. """Read the configuration.
Config format: key = command, e.g.: Config format: key = command, e.g.:
gg = scrollstart gg = scrollstart
""" """
sect = config.instance['keybind'] sect = config.instance['keybind']
if not sect.items(): if not sect.items():

View File

@ -27,6 +27,25 @@ from qutebrowser.commands.exceptions import (ArgumentCountError,
NoSuchCommandError) NoSuchCommandError)
def split_cmdline(text):
"""Convenience function to split a commandline into it's logical parts.
Args:
text: The string to split.
Return:
A list of strings.
"""
parser = CommandParser()
try:
parts = parser.parse(text)
except NoSuchCommandError:
parts = text.split(' ')
if text.endswith(' '):
parts.append('')
return parts
class SearchParser(QObject): class SearchParser(QObject):
"""Parse qutebrowser searches. """Parse qutebrowser searches.
@ -44,9 +63,9 @@ class SearchParser(QObject):
do_search = pyqtSignal(str, 'QWebPage::FindFlags') do_search = pyqtSignal(str, 'QWebPage::FindFlags')
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent)
self._text = None self._text = None
self._flags = 0 self._flags = 0
super().__init__(parent)
def _search(self, text, rev=False): def _search(self, text, rev=False):
"""Search for a text on the current page. """Search for a text on the current page.
@ -181,7 +200,7 @@ class CommandParser:
Raise: Raise:
NoSuchCommandError: if a command wasn't found. NoSuchCommandError: if a command wasn't found.
ArgumentCountError: if a command was called with the wrong count of ArgumentCountError: if a command was called with the wrong count of
arguments. arguments.
Return: Return:
True if command was called (handler returnstatus is ignored!). True if command was called (handler returnstatus is ignored!).
@ -210,22 +229,3 @@ class CommandParser:
raise raise
self._run(count=count) self._run(count=count)
return True return True
def split_cmdline(text):
"""Split a commandline into it's logical parts.
Arguments:
text: The string to split.
Return:
A list of strings.
"""
parser = CommandParser()
try:
parts = parser.parse(text)
except NoSuchCommandError:
parts = text.split(' ')
if text.endswith(' '):
parts.append('')
return parts

View File

@ -15,14 +15,17 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Contains various command utils and a global command dict.""" """Contains various command utils and a global command dict.
Module attributes:
cmd_dict: A mapping from command-strings to command objects.
"""
import inspect import inspect
from collections import Iterable from collections import Iterable
from qutebrowser.commands.command import Command from qutebrowser.commands.command import Command
# A mapping from command-strings to command objects.
cmd_dict = {} cmd_dict = {}
@ -52,7 +55,7 @@ class register: # pylint: disable=invalid-name
Gets called on parse-time with the decorator arguments. Gets called on parse-time with the decorator arguments.
Arguments: Args:
See class attributes. See class attributes.
""" """
self.name = name self.name = name
@ -70,7 +73,7 @@ class register: # pylint: disable=invalid-name
Doesn't actually decorate anything, but creates a Command object and Doesn't actually decorate anything, but creates a Command object and
registers it in the cmd_dict. registers it in the cmd_dict.
Arguments: Args:
func: The function to be decorated. func: The function to be decorated.
Return: Return:

View File

@ -20,6 +20,11 @@
This borrows a lot of ideas from configparser, but also has some things that This borrows a lot of ideas from configparser, but also has some things that
are fundamentally different. This is why nothing inherts from configparser, but are fundamentally different. This is why nothing inherts from configparser, but
we borrow some methods and classes from there where it makes sense. we borrow some methods and classes from there where it makes sense.
Module attributes:
instance: The "qutebrowser.conf" Config instance.
state: The "state" ReadWriteConfigParser instance.
cmd_history: The "cmd_history" LineConfigParser instance.
""" """
import os import os
@ -32,7 +37,6 @@ from collections.abc import MutableMapping
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject
#from qutebrowser.utils.misc import read_file
import qutebrowser.config.configdata as configdata import qutebrowser.config.configdata as configdata
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
@ -41,7 +45,7 @@ from qutebrowser.config.iniparsers import (ReadConfigParser,
ReadWriteConfigParser) ReadWriteConfigParser)
from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.config.lineparser import LineConfigParser
instance = None # The main config instance instance = None
state = None state = None
cmd_history = None cmd_history = None
@ -104,7 +108,7 @@ class Config(QObject):
def __init__(self, configdir, fname, parent=None): def __init__(self, configdir, fname, parent=None):
super().__init__(parent) super().__init__(parent)
self.sections = configdata.data self.sections = configdata.DATA
self._configparser = ReadConfigParser(configdir, fname) self._configparser = ReadConfigParser(configdir, fname)
self._configfile = os.path.join(configdir, fname) self._configfile = os.path.join(configdir, fname)
self._wrapper_args = { self._wrapper_args = {
@ -197,7 +201,7 @@ class Config(QObject):
def has_option(self, section, option): def has_option(self, section, option):
"""Check if option exists in section. """Check if option exists in section.
Arguments: Args:
section: The section name. section: The section name.
option: The option name option: The option name
@ -211,7 +215,7 @@ class Config(QObject):
def remove_option(self, section, option): def remove_option(self, section, option):
"""Remove an option. """Remove an option.
Arguments: Args:
section: The section where to remove an option. section: The section where to remove an option.
option: The option name to remove. option: The option name to remove.
@ -233,14 +237,7 @@ class Config(QObject):
def get_wrapper(self, section, option): def get_wrapper(self, section, option):
"""Get the value from a section/option. """Get the value from a section/option.
Wrapper for the get-command to output the value in the status bar Wrapper for the get-command to output the value in the status bar.
Arguments:
section: Section to get the value from
option: The option to get.
Return:
The value of the option.
""" """
val = self.get(section, option) val = self.get(section, option)
message.info("{} {} = {}".format(section, option, val)) message.info("{} {} = {}".format(section, option, val))
@ -248,10 +245,13 @@ class Config(QObject):
def get(self, section, option, raw=False): def get(self, section, option, raw=False):
"""Get the value from a section/option. """Get the value from a section/option.
Arguments: Args:
section: The section to get the option from. section: The section to get the option from.
option: The option name option: The option name
raw: Whether to get the uninterpolated, untransformed value. raw: Whether to get the uninterpolated, untransformed value.
Return:
The value of the option.
""" """
logging.debug("getting {} -> {}".format(section, option)) logging.debug("getting {} -> {}".format(section, option))
try: try:
@ -277,9 +277,6 @@ class Config(QObject):
"""Set an option. """Set an option.
Wrapper for self.set() to output exceptions in the status bar. Wrapper for self.set() to output exceptions in the status bar.
Arguments:
*args: Get passed to self.set().
""" """
try: try:
self.set('conf', section, option, value) self.set('conf', section, option, value)
@ -292,9 +289,6 @@ class Config(QObject):
"""Set a temporary option. """Set a temporary option.
Wrapper for self.set() to output exceptions in the status bar. Wrapper for self.set() to output exceptions in the status bar.
Arguments:
*args: Get passed to self.set().
""" """
try: try:
self.set('temp', section, option, value) self.set('temp', section, option, value)
@ -305,6 +299,7 @@ class Config(QObject):
"""Set an option. """Set an option.
Args: Args:
layer: A layer name as string (conf/temp/default).
section: The name of the section to change. section: The name of the section to change.
option: The name of the option to change. option: The name of the option to change.
value: The new value. value: The new value.
@ -376,7 +371,7 @@ class SectionProxy(MutableMapping):
def __init__(self, conf, name): def __init__(self, conf, name):
"""Create a view on a section. """Create a view on a section.
Arguments: Args:
conf: The Config object. conf: The Config object.
name: The section name. name: The section name.
""" """
@ -418,7 +413,7 @@ class SectionProxy(MutableMapping):
We deliberately don't support the default argument here, but have a raw We deliberately don't support the default argument here, but have a raw
argument instead. argument instead.
Arguments: Args:
option: The option name to get. option: The option name to get.
raw: Whether to get a raw value or not. raw: Whether to get a raw value or not.
""" """

View File

@ -15,7 +15,14 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Configuration data for config.py.""" """Configuration data for config.py.
Module attributes:
FIRST_COMMENT: The initial comment header to place in the config.
SECTION_DESC: A dictionary with descriptions for sections.
DATA: The config defaults, an OrderedDict of sections.
"""
from collections import OrderedDict from collections import OrderedDict
@ -96,7 +103,7 @@ SECTION_DESC = {
} }
data = OrderedDict([ DATA = OrderedDict([
('general', sect.KeyValue( ('general', sect.KeyValue(
('show_completion', ('show_completion',
SettingValue(types.Bool, "true"), SettingValue(types.Bool, "true"),

View File

@ -60,7 +60,7 @@ class BaseType:
"""A type used for a setting value. """A type used for a setting value.
Attributes: Class attributes:
valid_values: Possible values if they can be expressed as a fixed valid_values: Possible values if they can be expressed as a fixed
string. ValidValues instance. string. ValidValues instance.
typestr: The name of the type to appear in the config. typestr: The name of the type to appear in the config.
@ -96,7 +96,7 @@ class BaseType:
Raise: Raise:
ValidationError if the value was invalid. ValidationError if the value was invalid.
NotImplementedError if self.valid_values is not defined and this NotImplementedError if self.valid_values is not defined and this
method should be overridden. method should be overridden.
""" """
if self.valid_values is not None: if self.valid_values is not None:
if value not in self.valid_values: if value not in self.valid_values:
@ -120,7 +120,11 @@ class String(BaseType):
class Bool(BaseType): class Bool(BaseType):
"""Base class for a boolean setting.""" """Base class for a boolean setting.
Class attributes:
_BOOLEAN_STATES: A dictionary of strings mapped to their bool meanings.
"""
valid_values = ValidValues('true', 'false', show=False) valid_values = ValidValues('true', 'false', show=False)
typestr = 'bool' typestr = 'bool'
@ -198,7 +202,7 @@ class Perc(BaseType):
except ValueError: except ValueError:
raise ValidationError(value, "invalid percentage!") raise ValidationError(value, "invalid percentage!")
else: else:
if not 0 <= intval: if not intval >= 0:
raise ValidationError(value, "percentage needs to be >= 0!") raise ValidationError(value, "percentage needs to be >= 0!")

View File

@ -59,7 +59,7 @@ class LineConfigParser:
def write(self, fp, limit=-1): def write(self, fp, limit=-1):
"""Write the data to a file. """Write the data to a file.
Arguments: Args:
fp: A file object to write the data to. fp: A file object to write the data to.
limit: How many lines to write, or -1 for no limit. limit: How many lines to write, or -1 for no limit.
""" """

View File

@ -81,7 +81,7 @@ class Section:
def setv(self, layer, key, value): def setv(self, layer, key, value):
"""Set the value on a layer. """Set the value on a layer.
Arguments: Args:
layer: The layer to set the value on, an element name of the layer: The layer to set the value on, an element name of the
ValueLayers dict. ValueLayers dict.
key: The key of the element to set. key: The key of the element to set.
@ -166,7 +166,7 @@ class ValueList(Section):
def __init__(self, keytype, valtype, *defaults): def __init__(self, keytype, valtype, *defaults):
"""Wrap types over default values. Take care when overriding this. """Wrap types over default values. Take care when overriding this.
Arguments: Args:
keytype: The type to be used for keys. keytype: The type to be used for keys.
valtype: The type to be used for values. valtype: The type to be used for values.
*defaults: A (key, value) list of default values. *defaults: A (key, value) list of default values.

View File

@ -15,7 +15,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Utilities related to the look&feel of qutebrowser.""" """Utilities related to the look&feel of qutebrowser.
Module attributes:
_colordict: The global cached ColorDict.
_fontdict: The global cached FontDict.
"""
from functools import partial from functools import partial
@ -46,6 +51,12 @@ def set_register_stylesheet(obj):
"""Set the stylesheet for an object based on it's STYLESHEET attribute. """Set the stylesheet for an object based on it's STYLESHEET attribute.
Also, register an update when the config is changed. Also, register an update when the config is changed.
This isn't really good OOP, but it's the cleanest solution I could think
of.
Args:
obj: The object to set the stylesheet for and register.
Must have a STYLESHEET attribute.
""" """
obj.setStyleSheet(get_stylesheet(obj.STYLESHEET)) obj.setStyleSheet(get_stylesheet(obj.STYLESHEET))
config.instance.changed.connect(partial(_update_stylesheet, obj)) config.instance.changed.connect(partial(_update_stylesheet, obj))

View File

@ -93,7 +93,7 @@ class SettingValue:
def setv(self, layer, value): def setv(self, layer, value):
"""Set the value on a layer. """Set the value on a layer.
Arguments: Args:
layer: The layer to set the value on, an element name of the layer: The layer to set the value on, an element name of the
ValueLayers dict. ValueLayers dict.
value: The value to set. value: The value to set.

View File

@ -15,7 +15,13 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Bridge from QWebSettings to our own settings.""" """Bridge from QWebSettings to our own settings.
Module attributes:
MAPPING: A mapping from internal setting names to QWebSetting enum
constants.
settings: The global QWebSettings singleton instance.
"""
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings

View File

@ -86,7 +86,14 @@ class History:
self._tmphist = None self._tmphist = None
def previtem(self): def previtem(self):
"""Get the previous item in the temp history, or start browsing.""" """Get the previous item in the temp history.
start() needs to be called before calling this.
Raise:
ValueError if start() wasn't called.
HistoryEndReachedError if the first item was reached.
"""
if not self.browsing: if not self.browsing:
raise ValueError("Currently not browsing history") raise ValueError("Currently not browsing history")
try: try:
@ -95,7 +102,14 @@ class History:
raise HistoryEndReachedError raise HistoryEndReachedError
def nextitem(self): def nextitem(self):
"""Get the next item in the temp history.""" """Get the next item in the temp history.
start() needs to be called before calling this.
Raise:
ValueError if start() wasn't called.
HistoryEndReachedError if the last item was reached.
"""
if not self.browsing: if not self.browsing:
raise ValueError("Currently not browsing history") raise ValueError("Currently not browsing history")
try: try:

View File

@ -15,7 +15,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""The base completion model for completion in the command line.""" """The base completion model for completion in the command line.
Module attributes:
ROLE_MARKS: The role index used for marks.
"""
import logging import logging
from PyQt5.QtCore import Qt, QVariant, QAbstractItemModel, QModelIndex from PyQt5.QtCore import Qt, QVariant, QAbstractItemModel, QModelIndex

View File

@ -30,7 +30,7 @@ class SettingSectionCompletionModel(CompletionModel):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
cat = self.new_category("Config sections") cat = self.new_category("Config sections")
for name in configdata.data.keys(): for name in configdata.DATA.keys():
desc = configdata.SECTION_DESC[name].splitlines()[0].strip() desc = configdata.SECTION_DESC[name].splitlines()[0].strip()
self.new_item(cat, name, desc) self.new_item(cat, name, desc)
@ -44,7 +44,7 @@ class SettingOptionCompletionModel(CompletionModel):
def __init__(self, section, parent=None): def __init__(self, section, parent=None):
super().__init__(parent) super().__init__(parent)
cat = self.new_category("Config options for {}".format(section)) cat = self.new_category("Config options for {}".format(section))
sectdata = configdata.data[section] sectdata = configdata.DATA[section]
for name, _ in sectdata.items(): for name, _ in sectdata.items():
try: try:
desc = sectdata.descriptions[name] desc = sectdata.descriptions[name]
@ -62,7 +62,7 @@ class SettingValueCompletionModel(CompletionModel):
def __init__(self, section, option, parent=None): def __init__(self, section, option, parent=None):
super().__init__(parent) super().__init__(parent)
cat = self.new_category("Setting values for {}".format(option)) cat = self.new_category("Setting values for {}".format(option))
vals = configdata.data[section][option].typ.valid_values vals = configdata.DATA[section][option].typ.valid_values
if vals is None: if vals is None:
raise NoCompletionsError raise NoCompletionsError
for val in vals: for val in vals:

View File

@ -15,7 +15,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Handler functions for different qute:... pages.""" """Handler functions for different qute:... pages.
Module attributes:
_HTML_TEMPLATE: The HTML boilerplate used to convert text into html.
pyeval_output: The output of the last :pyeval command.
"""
import logging import logging
@ -52,6 +57,7 @@ def _get_html(title, snippet):
Return: Return:
HTML content as bytes. HTML content as bytes.
""" """
# FIXME we should html-escape the body
return _HTML_TEMPLATE.format(title=title, body=snippet).encode('UTF-8') return _HTML_TEMPLATE.format(title=title, body=snippet).encode('UTF-8')

View File

@ -41,7 +41,7 @@ def set_trace():
print(" from PyQt5 import QtCore; QtCore.pyqtRestoreInputHook()") print(" from PyQt5 import QtCore; QtCore.pyqtRestoreInputHook()")
print("before executing c(ontinue).") print("before executing c(ontinue).")
pyqtRemoveInputHook() pyqtRemoveInputHook()
return pdb_set_trace() pdb_set_trace()
def trace_lines(do_trace): def trace_lines(do_trace):
@ -51,7 +51,11 @@ def trace_lines(do_trace):
do_trace: Whether to start tracing (True) or stop it (False). do_trace: Whether to start tracing (True) or stop it (False).
""" """
def trace(frame, event, _): def trace(frame, event, _):
"""Trace function passed to sys.settrace.""" """Trace function passed to sys.settrace.
Return:
Itself, so tracing continues.
"""
print("{}, {}:{}".format(event, frame.f_code.co_filename, print("{}, {}:{}".format(event, frame.f_code.co_filename,
frame.f_lineno)) frame.f_lineno))
return trace return trace

View File

@ -15,19 +15,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Message singleton so we don't have to define unneeded signals.""" """Message singleton so we don't have to define unneeded signals.
Module attributes:
bridge: The MessageBridge instance.
"""
from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import QObject, pyqtSignal
class MessageBridge(QObject):
"""Bridge for messages to be shown in the statusbar."""
error = pyqtSignal(str)
info = pyqtSignal(str)
bridge = None bridge = None
@ -49,3 +45,11 @@ def error(message):
def info(message): def info(message):
"""Display an info message in the statusbar.""" """Display an info message in the statusbar."""
bridge.info.emit(message) bridge.info.emit(message)
class MessageBridge(QObject):
"""Bridge for messages to be shown in the statusbar."""
error = pyqtSignal(str)
info = pyqtSignal(str)

View File

@ -27,13 +27,6 @@ from PyQt5.QtCore import QUrl
import qutebrowser.config.config as config import qutebrowser.config.config as config
class SearchEngineError(Exception):
"""Exception raised when a search engine wasn't found."""
pass
def _get_search_url(txt): def _get_search_url(txt):
"""Get a search engine URL for a text. """Get a search engine URL for a text.
@ -202,3 +195,10 @@ def is_url(url):
return _is_url_naive(url) return _is_url_naive(url)
else: else:
raise ValueError("Invalid autosearch value") raise ValueError("Invalid autosearch value")
class SearchEngineError(Exception):
"""Exception raised when a search engine wasn't found."""
pass

View File

@ -15,11 +15,14 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Custom useful datatypes.""" """Custom useful datatypes.
Module attributes:
_UNSET: Used as default argument in the constructor so default can be None.
"""
import logging import logging
# Used as default argument in the constructor so default can be None.
_UNSET = object() _UNSET = object()
@ -27,10 +30,12 @@ class NeighborList:
"""A list of items which saves it current position. """A list of items which saves it current position.
Attributes: Class attributes:
BLOCK/WRAP/RAISE: Modes, see constructor documentation. BLOCK/WRAP/RAISE: Modes, see constructor documentation.
_items: A list of all items, accessed through item property.
Attributes:
idx: The current position in the list. idx: The current position in the list.
_items: A list of all items, accessed through item property.
_mode: The current mode. _mode: The current mode.
""" """

View File

@ -210,6 +210,9 @@ class BrowserTab(QWebView):
Emit: Emit:
scroll_pos_changed; If the scroll position changed. scroll_pos_changed; If the scroll position changed.
Return:
The superclass event return value.
""" """
frame = self.page_.mainFrame() frame = self.page_.mainFrame()
new_pos = (frame.scrollBarValue(Qt.Horizontal), new_pos = (frame.scrollBarValue(Qt.Horizontal),

View File

@ -53,10 +53,12 @@ class CompletionView(QTreeView):
Highlights completions based on marks in the ROLE_MARKS data. Highlights completions based on marks in the ROLE_MARKS data.
Class attributes:
STYLESHEET: The stylesheet template for the CompletionView.
Attributes: Attributes:
_model: The currently active filter model. _model: The currently active filter model.
_lastmodel: The model set in the last iteration. _lastmodel: The model set in the last iteration.
STYLESHEET: The stylesheet template for the CompletionView.
_completion_models: dict of available completion models. _completion_models: dict of available completion models.
_ignore_next: Whether to ignore the next cmd_text_changed signal. _ignore_next: Whether to ignore the next cmd_text_changed signal.
_enabled: Whether showing the CompletionView is enabled. _enabled: Whether showing the CompletionView is enabled.
@ -110,10 +112,10 @@ class CompletionView(QTreeView):
'section': CompletionFilterModel(SettingSectionCompletionModel( 'section': CompletionFilterModel(SettingSectionCompletionModel(
self)), self)),
} }
for sect in configdata.data.keys(): for sect in configdata.DATA.keys():
self._completion_models['option_' + sect] = CompletionFilterModel( self._completion_models['option_' + sect] = CompletionFilterModel(
SettingOptionCompletionModel(sect, self)) SettingOptionCompletionModel(sect, self))
for opt in configdata.data[sect].keys(): for opt in configdata.DATA[sect].keys():
try: try:
modelname = 'value_{}_{}'.format(sect, opt) modelname = 'value_{}_{}'.format(sect, opt)
self._completion_models[modelname] = ( self._completion_models[modelname] = (
@ -349,7 +351,7 @@ class _CompletionItemDelegate(QStyledItemDelegate):
in Qt: We use a QTextDocument to draw text. in Qt: We use a QTextDocument to draw text.
Args: Args:
index -- The QModelIndex of the item to draw. index: The QModelIndex of the item to draw.
""" """
if not self._opt.text: if not self._opt.text:
return return

View File

@ -77,9 +77,6 @@ class MainWindow(QWidget):
self.status = StatusBar() self.status = StatusBar()
self._vbox.addWidget(self.status) self._vbox.addWidget(self.status)
#self.status.resized.connect(self.completion.resize_to_bar)
#self.status.moved.connect(self.completion.move_to_bar)
#self.tabs.resized.connect(self.completion.on_browser_resized)
self.tabs.cur_progress.connect(self.status.prog.setValue) self.tabs.cur_progress.connect(self.status.prog.setValue)
self.tabs.cur_load_finished.connect(self.status.prog.hide) self.tabs.cur_load_finished.connect(self.status.prog.hide)
self.tabs.cur_load_finished.connect( self.tabs.cur_load_finished.connect(
@ -106,6 +103,10 @@ class MainWindow(QWidget):
#self.tabWidget.setCurrentIndex(0) #self.tabWidget.setCurrentIndex(0)
#QtCore.QMetaObject.connectSlotsByName(MainWindow) #QtCore.QMetaObject.connectSlotsByName(MainWindow)
def _set_default_geometry(self):
"""Set some sensible default geometry."""
self.setGeometry(QRect(50, 50, 800, 600))
@pyqtSlot(str, str) @pyqtSlot(str, str)
def on_config_changed(self, section, option): def on_config_changed(self, section, option):
"""Resize completion if config changed.""" """Resize completion if config changed."""
@ -129,10 +130,6 @@ class MainWindow(QWidget):
bottomright -= QPoint(0, self.inspector.height()) bottomright -= QPoint(0, self.inspector.height())
self.completion.setGeometry(QRect(topleft, bottomright)) self.completion.setGeometry(QRect(topleft, bottomright))
def _set_default_geometry(self):
"""Set some sensible default geometry."""
self.setGeometry(QRect(50, 50, 800, 600))
@cmdutils.register(instance='mainwindow', name='inspector') @cmdutils.register(instance='mainwindow', name='inspector')
def toggle_inspector(self): def toggle_inspector(self):
"""Toggle the web inspector.""" """Toggle the web inspector."""
@ -142,7 +139,7 @@ class MainWindow(QWidget):
else: else:
if not config.get('webkit', 'developer_extras_enabled'): if not config.get('webkit', 'developer_extras_enabled'):
self.status.disp_error("Please enable developer-extras before " self.status.disp_error("Please enable developer-extras before "
"using the webinspector!") "using the webinspector!")
else: else:
self.inspector.show() self.inspector.show()
self.resize_completion() self.resize_completion()

View File

@ -35,6 +35,9 @@ class StatusBar(QWidget):
"""The statusbar at the bottom of the mainwindow. """The statusbar at the bottom of the mainwindow.
Class attributes:
STYLESHEET: The stylesheet template.
Attributes: Attributes:
cmd: The Command widget in the statusbar. cmd: The Command widget in the statusbar.
txt: The Text widget in the statusbar. txt: The Text widget in the statusbar.
@ -46,7 +49,6 @@ class StatusBar(QWidget):
_stack: The QStackedLayout with cmd/txt widgets. _stack: The QStackedLayout with cmd/txt widgets.
_error: If there currently is an error, accessed through the error _error: If there currently is an error, accessed through the error
property. property.
STYLESHEET: The stylesheet template.
Signals: Signals:
resized: Emitted when the statusbar has resized, so the completion resized: Emitted when the statusbar has resized, so the completion
@ -59,6 +61,7 @@ class StatusBar(QWidget):
resized = pyqtSignal('QRect') resized = pyqtSignal('QRect')
moved = pyqtSignal('QPoint') moved = pyqtSignal('QPoint')
STYLESHEET = """ STYLESHEET = """
QWidget#StatusBar[error="false"] {{ QWidget#StatusBar[error="false"] {{
{color[statusbar.bg]} {color[statusbar.bg]}
@ -103,7 +106,6 @@ class StatusBar(QWidget):
self._hide_cmd_widget() self._hide_cmd_widget()
self._hbox.addLayout(self._stack) self._hbox.addLayout(self._stack)
#self._hbox.addStretch()
self.keystring = _KeyString(self) self.keystring = _KeyString(self)
self._hbox.addWidget(self.keystring) self._hbox.addWidget(self.keystring)
@ -248,7 +250,6 @@ class _Command(QLineEdit):
def __init__(self, statusbar): def __init__(self, statusbar):
super().__init__(statusbar) super().__init__(statusbar)
# FIXME
self._statusbar = statusbar self._statusbar = statusbar
self.setStyleSheet(""" self.setStyleSheet("""
QLineEdit { QLineEdit {
@ -343,7 +344,7 @@ class _Command(QLineEdit):
""" """
# FIXME we should consider the cursor position. # FIXME we should consider the cursor position.
text = self.text() text = self.text()
if text[0] in ':/?': if text[0] in keys.STARTCHARS:
prefix = text[0] prefix = text[0]
text = text[1:] text = text[1:]
else: else:
@ -398,7 +399,7 @@ class _Progress(QProgressBar):
"""The progress bar part of the status bar. """The progress bar part of the status bar.
Attributes: Class attributes:
STYLESHEET: The stylesheet template. STYLESHEET: The stylesheet template.
""" """
@ -583,12 +584,14 @@ class _Url(TextBase):
"""URL displayed in the statusbar. """URL displayed in the statusbar.
Class attributes:
STYLESHEET: The stylesheet template.
Attributes: Attributes:
_old_url: The URL displayed before the hover URL. _old_url: The URL displayed before the hover URL.
_old_urltype: The type of the URL displayed before the hover URL. _old_urltype: The type of the URL displayed before the hover URL.
_urltype: The current URL type. One of normal/ok/error/warn/hover. _urltype: The current URL type. One of normal/ok/error/warn/hover.
Accessed via the urltype property. Accessed via the urltype property.
STYLESHEET: The stylesheet template.
""" """
STYLESHEET = """ STYLESHEET = """

View File

@ -285,7 +285,7 @@ class TabbedBrowser(TabWidget):
if idx - count >= 0: if idx - count >= 0:
self.setCurrentIndex(idx - count) self.setCurrentIndex(idx - count)
else: else:
# FIXME # FIXME display message or wrap
pass pass
@cmdutils.register(instance='mainwindow.tabs', name='tabnext') @cmdutils.register(instance='mainwindow.tabs', name='tabnext')
@ -301,7 +301,7 @@ class TabbedBrowser(TabWidget):
if idx + count < self.count(): if idx + count < self.count():
self.setCurrentIndex(idx + count) self.setCurrentIndex(idx + count)
else: else:
# FIXME # FIXME display message or wrap
pass pass
@cmdutils.register(instance='mainwindow.tabs') @cmdutils.register(instance='mainwindow.tabs')

View File

@ -29,15 +29,13 @@ class TabWidget(QTabWidget):
"""The tabwidget used for TabbedBrowser. """The tabwidget used for TabbedBrowser.
Attributes: Class attributes:
STYLESHEET: The stylesheet template to be used. STYLESHEET: The stylesheet template to be used.
""" """
# FIXME there is still some ugly 1px white stripe from somewhere if we do # FIXME there is still some ugly 1px white stripe from somewhere if we do
# background-color: grey for QTabBar... # background-color: grey for QTabBar...
# pylint: disable=unused-argument
STYLESHEET = """ STYLESHEET = """
QTabWidget::pane {{ QTabWidget::pane {{
position: absolute; position: absolute;
@ -99,6 +97,7 @@ class TabWidget(QTabWidget):
except KeyError: except KeyError:
pass pass
# pylint: disable=unused-argument
@pyqtSlot(str, str) @pyqtSlot(str, str)
def on_config_changed(self, section, option): def on_config_changed(self, section, option):
"""Update attributes when config changed.""" """Update attributes when config changed."""

View File

@ -1,8 +1,3 @@
""" Run different codecheckers over a codebase.
Runs flake8, pylint, pep257 and a CRLF/whitespace/conflict-checker by default.
"""
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org> # Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# #
# This file is part of qutebrowser. # This file is part of qutebrowser.
@ -20,6 +15,15 @@ Runs flake8, pylint, pep257 and a CRLF/whitespace/conflict-checker by default.
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
""" Run different codecheckers over a codebase.
Runs flake8, pylint, pep257 and a CRLF/whitespace/conflict-checker by default.
Module attributes:
status: An OrderedDict for return status values.
option: A dictionary with options.
"""
import sys import sys
import subprocess import subprocess
import os import os
@ -56,10 +60,11 @@ options = {
def run(name, args=None): def run(name, args=None):
""" Run a checker via distutils with optional args. """Run a checker via distutils with optional args.
name -- Name of the checker/binary Arguments:
args -- Option list of arguments to pass name: Name of the checker/binary
args: Option list of arguments to pass
""" """
sys.argv = [name, options['target']] sys.argv = [name, options['target']]
if args is not None: if args is not None:
@ -84,6 +89,7 @@ def run(name, args=None):
def check_pep257(args=None): def check_pep257(args=None):
"""Run pep257 checker with args passed."""
sys.argv = ['pep257', options['target']] sys.argv = ['pep257', options['target']]
if args is not None: if args is not None:
sys.argv += args sys.argv += args
@ -97,14 +103,14 @@ def check_pep257(args=None):
def check_line(): def check_line():
"""Checks a filetree for CRLFs, conflict markers and weird whitespace""" """Run _check_file over a filetree."""
print("====== line ======") print("====== line ======")
ret = [] ret = []
try: try:
for (dirpath, dirnames, filenames) in os.walk(options['target']): for (dirpath, dirnames, filenames) in os.walk(options['target']):
for name in (e for e in filenames if e.endswith('.py')): for name in (e for e in filenames if e.endswith('.py')):
fn = os.path.join(dirpath, name) fn = os.path.join(dirpath, name)
ret.append(_check_line(fn)) ret.append(_check_file(fn))
status['line'] = all(ret) status['line'] = all(ret)
except Exception as e: except Exception as e:
print('{}: {}'.format(e.__class__.__name__, e)) print('{}: {}'.format(e.__class__.__name__, e))
@ -112,7 +118,8 @@ def check_line():
print() print()
def _check_line(fn): def _check_file(fn):
"""Check a single file for CRLFs, conflict markers and weird whitespace."""
with open(fn, 'rb') as f: with open(fn, 'rb') as f:
for line in f: for line in f:
if b'\r\n' in line: if b'\r\n' in line:
@ -132,6 +139,11 @@ def _check_line(fn):
def _get_args(checker): def _get_args(checker):
"""Construct the arguments for a given checker.
Return:
A list of commandline arguments.
"""
args = [] args = []
if checker == 'pylint': if checker == 'pylint':
try: try: