Start new config subsystem
This commit is contained in:
parent
dc18ec4e0d
commit
395acffdc4
@ -21,10 +21,12 @@ import os
|
|||||||
import io
|
import io
|
||||||
import os.path
|
import os.path
|
||||||
import logging
|
import logging
|
||||||
|
from collections import OrderedDict
|
||||||
from configparser import (ConfigParser, ExtendedInterpolation, NoSectionError,
|
from configparser import (ConfigParser, ExtendedInterpolation, NoSectionError,
|
||||||
NoOptionError)
|
NoOptionError)
|
||||||
|
|
||||||
from qutebrowser.utils.misc import read_file
|
from qutebrowser.utils.misc import read_file
|
||||||
|
from qutebrowser.config.options import *
|
||||||
|
|
||||||
config = None
|
config = None
|
||||||
state = None
|
state = None
|
||||||
@ -46,6 +48,47 @@ def init(confdir):
|
|||||||
state = Config(confdir, 'state', always_save=True)
|
state = Config(confdir, 'state', always_save=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigStructure:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.config = OrderedDict([
|
||||||
|
('general', KeyValueSection(
|
||||||
|
('show_completion', ShowCompletion()),
|
||||||
|
('completion_height', CompletionHeight()),
|
||||||
|
('ignorecase', IgnoreCase()),
|
||||||
|
('wrapsearch', WrapSearch()),
|
||||||
|
('startpage', StartPage()),
|
||||||
|
('auto_search', AutoSearch()),
|
||||||
|
('zoomlevels', ZoomLevels()),
|
||||||
|
('defaultzoom', DefaultZoom()),
|
||||||
|
)),
|
||||||
|
('tabbar', KeyValueSection(
|
||||||
|
('movable', Movable()),
|
||||||
|
('closebuttons', CloseButtons()),
|
||||||
|
('scrollbuttons', ScrollButtons()),
|
||||||
|
('position', Position()),
|
||||||
|
('select_on_remove', SelectOnRemove()),
|
||||||
|
('last_close', LastClose()),
|
||||||
|
)),
|
||||||
|
('searchengines', ValueListSection(
|
||||||
|
SearchEngineKeyValue()
|
||||||
|
)),
|
||||||
|
('keybind', ValueListSection(
|
||||||
|
KeybindKeyValue()
|
||||||
|
)),
|
||||||
|
('aliases', ValueListSection(
|
||||||
|
AliasKeyValue()
|
||||||
|
)),
|
||||||
|
('colors', KeyValueSection(
|
||||||
|
('completion.fg', CompletionFgColor()),
|
||||||
|
('completion.item.bg', CompletionItemBgColor()),
|
||||||
|
# FIXME ...
|
||||||
|
)),
|
||||||
|
('fonts', KeyValueSection(
|
||||||
|
)),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
class Config(ConfigParser):
|
class Config(ConfigParser):
|
||||||
|
|
||||||
"""Our own ConfigParser subclass.
|
"""Our own ConfigParser subclass.
|
||||||
|
370
qutebrowser/config/options.py
Normal file
370
qutebrowser/config/options.py
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
# Copyright 2014 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/>.
|
||||||
|
|
||||||
|
"""Setting options used for qutebrowser."""
|
||||||
|
|
||||||
|
from qutebrowser.config.templates import *
|
||||||
|
|
||||||
|
class ShowCompletion(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether to show the autocompletion window or not."""
|
||||||
|
|
||||||
|
default = "true"
|
||||||
|
|
||||||
|
class CompletionHeight(SettingValue):
|
||||||
|
|
||||||
|
"""The height of the completion, in px or as percentage of the window."""
|
||||||
|
|
||||||
|
default = "50%"
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if value.endswith('%'):
|
||||||
|
try:
|
||||||
|
intval = int(value.rstrip('%'))
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return 0 <= intval <= 100
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
intval = int(value)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return intval > 0
|
||||||
|
|
||||||
|
|
||||||
|
class IgnoreCase(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether to do case-insensitive searching."""
|
||||||
|
|
||||||
|
default = "true"
|
||||||
|
|
||||||
|
|
||||||
|
class WrapSearch(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether to wrap search to the top when arriving at the end."""
|
||||||
|
|
||||||
|
default = "true"
|
||||||
|
|
||||||
|
|
||||||
|
class StartPage(ListSettingValue):
|
||||||
|
|
||||||
|
"""The default page(s) to open at the start, separated with commas."""
|
||||||
|
|
||||||
|
default = "http://www.duckduckgo.com/"
|
||||||
|
|
||||||
|
|
||||||
|
class AutoSearch(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether to start a search when something else than an URL is entered."""
|
||||||
|
|
||||||
|
values = [("naive", "Use simple/naive check."),
|
||||||
|
("dns", "Use DNS requests (might be slow!)."),
|
||||||
|
("false": "Never search automatically.")]
|
||||||
|
default = "naive"
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if value.lower() in ["naive", "dns"]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return super().validate(value)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return super().validate(value)
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
if value.lower() in ["naive", "dns"]:
|
||||||
|
return value.lower()
|
||||||
|
elif super().transform(value):
|
||||||
|
# boolean true is an alias for naive matching
|
||||||
|
return "naive"
|
||||||
|
else:
|
||||||
|
return "false"
|
||||||
|
|
||||||
|
|
||||||
|
class ZoomLevels(IntListSettingValue):
|
||||||
|
|
||||||
|
"""The available zoom levels, separated by commas."""
|
||||||
|
|
||||||
|
default = "25,33,50,67,75,90,100,110,125,150,175,200,250,300,400,500"
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultZoom(IntSettingValue):
|
||||||
|
|
||||||
|
"""The default zoom level."""
|
||||||
|
|
||||||
|
# FIXME we might want to validate if defaultzoom is in zoomlevels...
|
||||||
|
|
||||||
|
default = "100"
|
||||||
|
|
||||||
|
|
||||||
|
class Movable(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether tabs should be movable."""
|
||||||
|
|
||||||
|
default = "true"
|
||||||
|
|
||||||
|
|
||||||
|
class CloseButtons(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether tabs should have close-buttons."""
|
||||||
|
|
||||||
|
default = "false"
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollButtons(BoolSettingValue):
|
||||||
|
|
||||||
|
"""Whether there should be scroll buttons if there are too many tabs."""
|
||||||
|
|
||||||
|
default = "true"
|
||||||
|
|
||||||
|
|
||||||
|
class Position(SettingValue):
|
||||||
|
|
||||||
|
"""The position of the tab bar."""
|
||||||
|
|
||||||
|
values = ["north", "south", "east", "west"]
|
||||||
|
default = "north"
|
||||||
|
|
||||||
|
|
||||||
|
class SelectOnRemove(SettingValue):
|
||||||
|
|
||||||
|
"""Which tab to select when the focused tab is removed."""
|
||||||
|
|
||||||
|
values = [("left", "Select the tab on the left."),
|
||||||
|
("right", "Select the tab on the right."),
|
||||||
|
("previous", "Select the previously selected tab.")]
|
||||||
|
default = "previous"
|
||||||
|
|
||||||
|
|
||||||
|
class LastClose(SettingValue):
|
||||||
|
|
||||||
|
"""Behaviour when the last tab is closed."""
|
||||||
|
|
||||||
|
values = [("ignore", "Don't do anything."),
|
||||||
|
("blank", "Load about:blank."),
|
||||||
|
("quit", "Quit qutebrowser.")]
|
||||||
|
default = "ignore"
|
||||||
|
|
||||||
|
### FIXME what to do with list-style sections?
|
||||||
|
|
||||||
|
class SearchEngine(SettingValue):
|
||||||
|
|
||||||
|
"""A search engine setting."""
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
return "{}" in value
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Text color of the completion widget."""
|
||||||
|
|
||||||
|
default = "#333333"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionItemBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of completion widget items."""
|
||||||
|
|
||||||
|
default = "white"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionCategoryBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the completion widget category headers."""
|
||||||
|
|
||||||
|
default = ("completion.category.bg = qlineargradient("
|
||||||
|
"x1:0, y1:0, x2:0, y2:1, stop:0 #e4e4e4, stop:1 #dbdbdb")
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionCategoryTopBorderColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Top border color of the completion widget category headers."""
|
||||||
|
|
||||||
|
default = "#808080"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionCategoryBottomBorderColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Bottom border color of the completion widget category headers."""
|
||||||
|
|
||||||
|
default = "#bbbbbb"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionItemSelectedFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the selected completion item."""
|
||||||
|
|
||||||
|
default = "#333333"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionItemSelectedBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the selected completion item."""
|
||||||
|
|
||||||
|
default = "#ffec8b"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionItemSelectedTopBorderColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Top border color of the selected completion item."""
|
||||||
|
|
||||||
|
default = "#f2f2c0"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionItemSelectedBottomBorderColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Bottom border color of the selected completion item."""
|
||||||
|
|
||||||
|
default = "#ffec8b"
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionMatchFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the matched text in the completion."""
|
||||||
|
|
||||||
|
default = "red"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the statusbar."""
|
||||||
|
|
||||||
|
default = "black"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the statusbar."""
|
||||||
|
|
||||||
|
default = "white"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarFgErrorColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the statusbar if there was an error."""
|
||||||
|
|
||||||
|
default = "${statusbar.fg}"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarBgErrorColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the statusbar if there was an error."""
|
||||||
|
|
||||||
|
default = "red"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarProgressBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the progress bar."""
|
||||||
|
|
||||||
|
default = "white"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarUrlFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Default foreground color of the URL in the statusbar."""
|
||||||
|
|
||||||
|
default = "${statusbar.fg}"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarUrlSuccessFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the URL in the statusbar on successful load."""
|
||||||
|
|
||||||
|
default = "lime"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarUrlErrorFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the URL in the statusbar on error."""
|
||||||
|
|
||||||
|
default = "orange"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarUrlWarnFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the URL in the statusbar when there's a warning."""
|
||||||
|
|
||||||
|
default = "yellow"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarUrlHoverFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the URL in the statusbar for hovered links."""
|
||||||
|
|
||||||
|
default = "aqua"
|
||||||
|
|
||||||
|
|
||||||
|
class TabFgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Foreground color of the tabbar."""
|
||||||
|
|
||||||
|
default = "white"
|
||||||
|
|
||||||
|
|
||||||
|
class TabBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the tabbar."""
|
||||||
|
|
||||||
|
default = "grey"
|
||||||
|
|
||||||
|
|
||||||
|
class TabSelectedBgColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Background color of the tabbar for the selected tab."""
|
||||||
|
|
||||||
|
default = "black"
|
||||||
|
|
||||||
|
|
||||||
|
class TabSeperatorColor(ColorSettingValue):
|
||||||
|
|
||||||
|
"""Color for the tab seperator."""
|
||||||
|
|
||||||
|
default = "white"
|
||||||
|
|
||||||
|
|
||||||
|
class MonospaceFonts(FontSettingValue):
|
||||||
|
|
||||||
|
"""Default monospace fonts."""
|
||||||
|
|
||||||
|
default = ('Monospace, "DejaVu Sans Mono", Consolas, Monaco, '
|
||||||
|
'"Bitstream Vera Sans Mono", "Andale Mono", "Liberation Mono", '
|
||||||
|
'"Courier New", Courier, monospace, Fixed, Terminal')
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionFont(FontSettingValue):
|
||||||
|
|
||||||
|
"""Font used in the completion widget."""
|
||||||
|
|
||||||
|
default = "8pt ${_monospace}"
|
||||||
|
|
||||||
|
|
||||||
|
class TabbarFont(FontSettingValue):
|
||||||
|
|
||||||
|
"""Font used in the tabbar."""
|
||||||
|
|
||||||
|
default = "8pt ${_monospace}"
|
||||||
|
|
||||||
|
|
||||||
|
class StatusbarFont(FontSettingValue):
|
||||||
|
|
||||||
|
"""Font used in the statusbar."""
|
||||||
|
|
||||||
|
default = "8pt ${_monospace}"
|
162
qutebrowser/config/templates.py
Normal file
162
qutebrowser/config/templates.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Copyright 2014 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/>.
|
||||||
|
|
||||||
|
"""Templates for setting options."""
|
||||||
|
|
||||||
|
import qutebrowser.commands.utils as cmdutils
|
||||||
|
|
||||||
|
class SettingValue:
|
||||||
|
|
||||||
|
"""Base class for settings. The docstring is used as a description."""
|
||||||
|
|
||||||
|
# Possible values, if they are fixed.
|
||||||
|
# Either a list of strings, or a list of (value, desc) tuples.
|
||||||
|
values = None
|
||||||
|
|
||||||
|
# Default value if user has not overriden it, as a string.
|
||||||
|
default = None
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
"""Transform the setting value.
|
||||||
|
|
||||||
|
This method can assume the value is indeed a valid value.
|
||||||
|
|
||||||
|
The default implementation returns the original value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to transform.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
The transformed value.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
"""Validate value against possible values.
|
||||||
|
|
||||||
|
The default implementation checks the value against self.values if it
|
||||||
|
was defined.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to validate.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
Ture if validation succeeded, False otherwise.
|
||||||
|
|
||||||
|
Raise:
|
||||||
|
NotImplementedError if self.values is not defined and this method
|
||||||
|
should be overridden.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.values is not None:
|
||||||
|
return value in self.values
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class BoolSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for a boolean setting."""
|
||||||
|
values = ['true', 'false']
|
||||||
|
|
||||||
|
# Taken from configparser
|
||||||
|
_BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True,
|
||||||
|
'0': False, 'no': False, 'false': False, 'off': False}
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
return self._BOOLEAN_STATES[value.lower()]
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
return value.lower() in self._BOOLEAN_STATES
|
||||||
|
|
||||||
|
|
||||||
|
class IntSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for an integer setting."""
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
try:
|
||||||
|
int(value)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ListSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for a (string-)list setting."""
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
return value.split(',')
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class IntListSettingValue(ListSettingValue):
|
||||||
|
|
||||||
|
"""Base class for an int-list setting."""
|
||||||
|
|
||||||
|
def transform(self, value):
|
||||||
|
vals = super().transform(value)
|
||||||
|
return map(int, vals)
|
||||||
|
|
||||||
|
def validate(self, value)
|
||||||
|
try:
|
||||||
|
self.transform(value)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class CommandSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for a command value with arguments."""
|
||||||
|
|
||||||
|
values = cmdutils.cmd_dict.values()
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
cp = cmdutils.CommandParser()
|
||||||
|
try:
|
||||||
|
cp.parse(value)
|
||||||
|
except cmdutils.NoSuchCommandError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ColorSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for a color value."""
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
# FIXME validate colors
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class FontSettingValue(SettingValue):
|
||||||
|
|
||||||
|
"""Base class for a font value."""
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
# FIXME validate fonts
|
||||||
|
return True
|
Loading…
Reference in New Issue
Block a user