diff --git a/qutebrowser/commands/keys.py b/qutebrowser/commands/keys.py index 407a4b861..ed217636f 100644 --- a/qutebrowser/commands/keys.py +++ b/qutebrowser/commands/keys.py @@ -245,16 +245,16 @@ class KeyParser(QObject): """ for (key, cmd) in sect.items(): - if key.value.startswith('@') and key.value.endswith('@'): + if key.startswith('@') and key.endswith('@'): # normalize keystring - keystr = self._normalize_keystr(key.value.strip('@')) + keystr = self._normalize_keystr(key.strip('@')) logging.debug('registered mod key: {} -> {}'.format(keystr, cmd.value)) self._modifier_bindings[keystr] = cmd.value else: - logging.debug('registered key: {} -> {}'.format(key.value, + logging.debug('registered key: {} -> {}'.format(key, cmd.value)) - self._bindings[key.value] = cmd.value + self._bindings[key] = cmd.value def handle(self, e): """Handle a new keypress and call the respective handlers. diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index b194221f9..d1b35fe51 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -27,8 +27,9 @@ from configparser import (ConfigParser, ExtendedInterpolation, NoSectionError, NoOptionError) #from qutebrowser.utils.misc import read_file -import qutebrowser.config.options as opt +import qutebrowser.config.conftypes as types import qutebrowser.config.sections as sect +from qutebrowser.config.templates import SettingValue config = None state = None @@ -119,66 +120,212 @@ class NewConfig: } def __init__(self): + MONOSPACE = ('Monospace, "DejaVu Sans Mono", Consolas, Monaco, ' + '"Bitstream Vera Sans Mono", "Andale Mono", ' + '"Liberation Mono", "Courier New", Courier, monospace, ' + 'Fixed, Terminal') + self.config = OrderedDict([ ('general', sect.KeyValue( - ('show_completion', opt.ShowCompletion()), - ('completion_height', opt.CompletionHeight()), - ('ignorecase', opt.IgnoreCase()), - ('wrapsearch', opt.WrapSearch()), - ('startpage', opt.StartPage()), - ('auto_search', opt.AutoSearch()), - ('zoomlevels', opt.ZoomLevels()), - ('defaultzoom', opt.DefaultZoom()), + ('show_completion', + SettingValue(types.Bool, "true"), + "Whether to show the autocompletion window or not."), + + ('completion_height', + SettingValue(types.PercOrInt, "50%"), + "The height of the completion, in px or as percentage of the " + "window."), + + ('ignorecase', + SettingValue(types.Bool, "true"), + "Whether to do case-insensitive searching."), + + ('wrapsearch', + SettingValue(types.Bool, "true"), + "Whether to wrap search to the top when arriving at the " + "end."), + + ('startpage', + SettingValue(types.List, "http://www.duckduckgo.com"), + "The default page(s) to open at the start, separated with " + "commas."), + + ('auto_search', + SettingValue(types.AutoSearch, "naive"), + "Whether to start a search when something else than an URL " + "is entered."), + + ('zoomlevels', + SettingValue(types.Int, "25,33,50,67,75,90,100,110,125,150," + "175,200,250,300,400,500"), + "The available zoom levels, separated by commas."), + + ('defaultzoom', + SettingValue(types.Int, "100"), + "The default zoom level."), )), + ('tabbar', sect.KeyValue( - ('movable', opt.Movable()), - ('closebuttons', opt.CloseButtons()), - ('scrollbuttons', opt.ScrollButtons()), - ('position', opt.Position()), - ('select_on_remove', opt.SelectOnRemove()), - ('last_close', opt.LastClose()), + ('movable', + SettingValue(types.Bool, "true"), + "Whether tabs should be movable."), + + ('closebuttons', + SettingValue(types.Bool, "false"), + "Whether tabs should have close-buttons."), + + ('scrollbuttons', + SettingValue(types.Bool, "true"), + "Whether there should be scroll buttons if there are too " + "many tabs."), + + ('position', + SettingValue(types.Position, "north"), + "The position of the tab bar."), + + ('select_on_remove', + SettingValue(types.SelectOnRemove, "previous"), + "Which tab to select when the focused tab is removed."), + + ('last_close', + SettingValue(types.LastClose, "ignore"), + "Behaviour when the last tab is closed."), )), + ('searchengines', sect.SearchEngines()), + ('keybind', sect.KeyBindings()), + ('aliases', sect.Aliases()), + ('colors', sect.KeyValue( - ('completion.fg', opt.CompletionFgColor()), - ('completion.item.bg', opt.CompletionItemBgColor()), - ('completion.category.bg', opt.CompletionCategoryBgColor()), + ('completion.fg', + SettingValue(types.Color, "#333333"), + "Text color of the completion widget."), + + ('completion.item.bg', + SettingValue(types.Color, "white"), + "Background color of completion widget items."), + + ('completion.category.bg', + SettingValue( + types.Color, + "qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #e4e4e4, " + "stop:1 #dbdbdb)"), + "Background color of the completion widget category " + "headers."), + ('completion.category.border.top', - opt.CompletionCategoryTopBorderColor()), + SettingValue(types.Color, "#808080"), + "Top border color of the completion widget category " + "headers."), + ('completion.category.border.bottom', - opt.CompletionCategoryBottomBorderColor()), + SettingValue(types.Color, "#bbbbbb"), + "Bottom border color of the completion widget category " + "headers."), + ('completion.item.selected.fg', - opt.CompletionItemSelectedFgColor()), + SettingValue(types.Color, "#333333"), + "Foreground color of the selected completion item."), + ('completion.item.selected.bg', - opt.CompletionItemSelectedBgColor()), + SettingValue(types.Color, "#ffec8b"), + "Background color of the selected completion item."), + ('completion.item.selected.border.top', - opt.CompletionItemSelectedTopBorderColor()), + SettingValue(types.Color, "#f2f2c0"), + "Top border color of the completion widget category " + "headers."), + ('completion.item.selected.border.bottom', - opt.CompletionCategoryBottomBorderColor()), + SettingValue(types.Color, "#ffec8b"), + "Bottom border color of the selected completion item."), + ('completion.match.fg', - opt.CompletionMatchFgColor()), - ('statusbar.bg', opt.StatusbarBgColor()), - ('statusbar.fg', opt.StatusbarFgColor()), - ('statusbar.bg.error', opt.StatusbarBgErrorColor()), - ('statusbar.fg.error', opt.StatusbarFgErrorColor()), - ('statusbar.progress.bg', opt.StatusbarProgressBgColor()), - ('statusbar.url.fg', opt.StatusbarUrlFgColor()), - ('statusbar.url.fg.success', opt.StatusbarUrlHoverFgColor()), - ('statusbar.url.fg.error', opt.StatusbarUrlErrorFgColor()), - ('statusbar.url.fg.warn', opt.StatusbarUrlWarnFgColor()), - ('statusbar.url.fg.hover', opt.StatusbarUrlHoverFgColor()), - ('tab.fg', opt.TabFgColor()), - ('tab.bg', opt.TabBgColor()), - ('tab.bg.selected', opt.TabSelectedBgColor()), - ('tab.seperator', opt.TabSeperatorColor()), + SettingValue(types.Color, "red"), + "Foreground color of the matched text in the completion."), + + ('statusbar.bg', + SettingValue(types.Color, "black"), + "Foreground color of the statusbar."), + + ('statusbar.fg', + SettingValue(types.Color, "white"), + "Foreground color of the statusbar."), + + ('statusbar.bg.error', + SettingValue(types.Color, "red"), + "Background color of the statusbar if there was an error."), + + ('statusbar.fg.error', + SettingValue(types.Color, "white", "${statusbar.fg}"), + "Foreground color of the statusbar if there was an error."), + + ('statusbar.progress.bg', + SettingValue(types.Color, "white"), + "Background color of the progress bar."), + + ('statusbar.url.fg', + SettingValue(types.Color, "white", "${statusbar.fg}"), + "Default foreground color of the URL in the statusbar."), + + ('statusbar.url.fg.success', + SettingValue(types.Color, "lime"), + "Foreground color of the URL in the statusbar on successful " + "load."), + + ('statusbar.url.fg.error', + SettingValue(types.Color, "orange"), + "Foreground color of the URL in the statusbar on error."), + + ('statusbar.url.fg.warn', + SettingValue(types.Color, "yellow"), + "Foreground color of the URL in the statusbar when there's a " + "warning."), + + ('statusbar.url.fg.hover', + SettingValue(types.Color, "aqua"), + "Foreground color of the URL in the statusbar for hovered " + "links."), + + ('tab.fg', + SettingValue(types.Color, "white"), + "Foreground color of the tabbar."), + + ('tab.bg', + SettingValue(types.Color, "grey"), + "Background color of the tabbar."), + + ('tab.bg.selected', + SettingValue(types.Color, "black"), + "Background color of the tabbar for the selected tab."), + + ('tab.seperator', + SettingValue(types.Color, "white"), + "Color for the tab seperator."), )), + ('fonts', sect.KeyValue( - ('_monospace', opt.MonospaceFonts()), - ('completion', opt.CompletionFont()), - ('tabbar', opt.TabbarFont()), - ('statusbar', opt.StatusbarFont()), + ('_monospace', + SettingValue(types.Font, MONOSPACE), + "Default monospace fonts."), + + ('completion', + SettingValue(types.Font, "8pt " + MONOSPACE, + "8pt ${_monospace}"), + "Font used in the completion widget."), + + ('tabbar', + SettingValue(types.Font, "8pt " + MONOSPACE, + "8pt ${_monospace}"), + "Font used in the tabbar."), + + ('statusbar', + SettingValue(types.Font, "8pt " + MONOSPACE, + "8pt ${_monospace}"), + "Font used in the statusbar."), + )), ]) diff --git a/qutebrowser/config/conftypes.py b/qutebrowser/config/conftypes.py new file mode 100644 index 000000000..cd8d82e08 --- /dev/null +++ b/qutebrowser/config/conftypes.py @@ -0,0 +1,294 @@ +# Copyright 2014 Florian Bruhin (The Compiler) +# +# 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 . + +"""Setting options used for qutebrowser.""" + +import qutebrowser.commands.utils as cmdutils + + +class BaseType: + + """A type used for a setting value. + + Attributes: + valid_values: Possible values if they can be expressed as a fixed + string. Either a list of strings, or a list of (value, + desc) tuples. + # FIXME actually handle tuples and stuff when validating + typestr: The name of the type to appear in the config. + + """ + + typestr = None + valid_values = 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. + + Return: + The transformed value. + + """ + return value + + def validate(self): + """Validate value against possible values. + + The default implementation checks the value against self.valid_values + if it was defined. + + Return: + Ture if validation succeeded, False otherwise. + + Raise: + NotImplementedError if self.valid_values is not defined and this + method should be overridden. + + """ + if self.valid_values is not None: + return self.value in self.valid_values + else: + raise NotImplementedError + +class String(BaseType): + + """Base class for a string setting (case-insensitive).""" + + typestr = 'string' + + def transform(self, value): + return value.lower() + + +class Bool(BaseType): + + """Base class for a boolean setting.""" + + valid_values = ['true', 'false'] + typestr = 'bool' + + # 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): + return self.value.lower() in self._BOOLEAN_STATES + + +class Int(BaseType): + + """Base class for an integer setting.""" + + typestr = 'int' + + def transform(self, value): + return int(value) + + def validate(self): + try: + int(self.value) + except ValueError: + return False + else: + return True + + +class List(BaseType): + + """Base class for a (string-)list setting.""" + + typestr = 'string-list' + + def transform(self, value): + return value.split(',') + + def validate(self): + return True + + +class IntList(List): + + """Base class for an int-list setting.""" + + typestr = 'int-list' + + def transform(self, value): + vals = super().transform(value) + return map(int, vals) + + def validate(self): + try: + self.transform(self.value) + except ValueError: + return False + else: + return True + + +class PercOrInt(BaseType): + + """Percentage or integer.""" + + def validate(self): + if self.value.endswith('%'): + try: + intval = int(self.value.rstrip('%')) + except ValueError: + return False + else: + return 0 <= intval <= 100 + else: + try: + intval = int(self.value) + except ValueError: + return False + else: + return intval > 0 + + +class Command(BaseType): + + """Base class for a command value with arguments.""" + + typestr = 'command' + + valid_values = cmdutils.cmd_dict.items() + + def validate(self): + # We need to import this here to avoid circular dependencies + from qutebrowser.commands.parsers import (CommandParser, + NoSuchCommandError) + cp = CommandParser() + try: + cp.parse(self.value) + except NoSuchCommandError: + return False + else: + return True + + +class Color(BaseType): + + """Base class for a color value.""" + + typestr = 'color' + + def validate(self): + # FIXME validate colors + return True + + +class Font(BaseType): + + """Base class for a font value.""" + + typestr = 'font' + + def validate(self): + # FIXME validate fonts + return True + + +class SearchEngineName(BaseType): + + """A search engine name.""" + + def validate(self): + return True + + +class SearchEngineUrl(BaseType): + + """A search engine URL.""" + + def validate(self): + return "{}" in self.value + + +class KeyBindingName(BaseType): + + """The name (keys) of a keybinding.""" + + def validate(self): + # FIXME can we validate anything here? + return True + + + +class AutoSearch(Bool): + + """Whether to start a search when something else than an URL is entered.""" + + valid_values = [("naive", "Use simple/naive check."), + ("dns", "Use DNS requests (might be slow!)."), + ("false", "Never search automatically.")] + + def validate(self): + if self.value.lower() in ["naive", "dns"]: + return True + else: + return super().validate(self.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 Position(String): + + """The position of the tab bar.""" + + valid_values = ["north", "south", "east", "west"] + + +class SelectOnRemove(String): + + """Which tab to select when the focused tab is removed.""" + + valid_values = [("left", "Select the tab on the left."), + ("right", "Select the tab on the right."), + ("previous", "Select the previously selected tab.")] + + +class LastClose(String): + + """Behaviour when the last tab is closed.""" + + valid_values = [("ignore", "Don't do anything."), + ("blank", "Load about:blank."), + ("quit", "Quit qutebrowser.")] + + +class KeyBinding(Command): + + """The command of a keybinding.""" + + pass + + diff --git a/qutebrowser/config/options.py b/qutebrowser/config/options.py deleted file mode 100644 index bdf664ef8..000000000 --- a/qutebrowser/config/options.py +++ /dev/null @@ -1,397 +0,0 @@ -# Copyright 2014 Florian Bruhin (The Compiler) -# -# 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 . - -"""Setting options used for qutebrowser.""" - -import qutebrowser.config.templates as template - - -class ShowCompletion(template.BoolSettingValue): - - """Whether to show the autocompletion window or not.""" - - default = "true" - - -class CompletionHeight(template.SettingValue): - - """The height of the completion, in px or as percentage of the window.""" - - default = "50%" - - def validate(self): - if self.value.endswith('%'): - try: - intval = int(self.value.rstrip('%')) - except ValueError: - return False - else: - return 0 <= intval <= 100 - else: - try: - intval = int(self.value) - except ValueError: - return False - else: - return intval > 0 - - -class IgnoreCase(template.BoolSettingValue): - - """Whether to do case-insensitive searching.""" - - default = "true" - - -class WrapSearch(template.BoolSettingValue): - - """Whether to wrap search to the top when arriving at the end.""" - - default = "true" - - -class StartPage(template.ListSettingValue): - - """The default page(s) to open at the start, separated with commas.""" - - default = "http://www.duckduckgo.com/" - - -class AutoSearch(template.BoolSettingValue): - - """Whether to start a search when something else than an URL is entered.""" - - valid_values = [("naive", "Use simple/naive check."), - ("dns", "Use DNS requests (might be slow!)."), - ("false", "Never search automatically.")] - default = "naive" - - def validate(self): - if self.value.lower() in ["naive", "dns"]: - return True - else: - return super().validate(self.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(template.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(template.IntSettingValue): - - """The default zoom level.""" - - # FIXME we might want to validate if defaultzoom is in zoomlevels... - - default = "100" - - -class Movable(template.BoolSettingValue): - - """Whether tabs should be movable.""" - - default = "true" - - -class CloseButtons(template.BoolSettingValue): - - """Whether tabs should have close-buttons.""" - - default = "false" - - -class ScrollButtons(template.BoolSettingValue): - - """Whether there should be scroll buttons if there are too many tabs.""" - - default = "true" - - -class Position(template.StringSettingValue): - - """The position of the tab bar.""" - - valid_values = ["north", "south", "east", "west"] - default = "north" - - -class SelectOnRemove(template.StringSettingValue): - - """Which tab to select when the focused tab is removed.""" - - valid_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(template.StringSettingValue): - - """Behaviour when the last tab is closed.""" - - valid_values = [("ignore", "Don't do anything."), - ("blank", "Load about:blank."), - ("quit", "Quit qutebrowser.")] - default = "ignore" - - -class CompletionFgColor(template.ColorSettingValue): - - """Text color of the completion widget.""" - - default = "#333333" - - -class CompletionItemBgColor(template.ColorSettingValue): - - """Background color of completion widget items.""" - - default = "white" - - -class CompletionCategoryBgColor(template.ColorSettingValue): - - """Background color of the completion widget category headers.""" - - default = ("qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #e4e4e4, " - "stop:1 #dbdbdb)") - - -class CompletionCategoryTopBorderColor(template.ColorSettingValue): - - """Top border color of the completion widget category headers.""" - - default = "#808080" - - -class CompletionCategoryBottomBorderColor(template.ColorSettingValue): - - """Bottom border color of the completion widget category headers.""" - - default = "#bbbbbb" - - -class CompletionItemSelectedFgColor(template.ColorSettingValue): - - """Foreground color of the selected completion item.""" - - default = "#333333" - - -class CompletionItemSelectedBgColor(template.ColorSettingValue): - - """Background color of the selected completion item.""" - - default = "#ffec8b" - - -class CompletionItemSelectedTopBorderColor(template.ColorSettingValue): - - """Top border color of the selected completion item.""" - - default = "#f2f2c0" - - -class CompletionItemSelectedBottomBorderColor(template.ColorSettingValue): - - """Bottom border color of the selected completion item.""" - - default = "#ffec8b" - - -class CompletionMatchFgColor(template.ColorSettingValue): - - """Foreground color of the matched text in the completion.""" - - default = "red" - - -class StatusbarBgColor(template.ColorSettingValue): - - """Background color of the statusbar.""" - - default = "black" - - -class StatusbarFgColor(template.ColorSettingValue): - - """Foreground color of the statusbar.""" - - default = "white" - - -class StatusbarFgErrorColor(template.ColorSettingValue): - - """Foreground color of the statusbar if there was an error.""" - - default = StatusbarFgColor.default - default_conf = "${statusbar.fg}" - - -class StatusbarBgErrorColor(template.ColorSettingValue): - - """Background color of the statusbar if there was an error.""" - - default = "red" - - -class StatusbarProgressBgColor(template.ColorSettingValue): - - """Background color of the progress bar.""" - - default = "white" - - -class StatusbarUrlFgColor(template.ColorSettingValue): - - """Default foreground color of the URL in the statusbar.""" - - default = StatusbarFgColor.default - default_conf = "${statusbar.fg}" - - -class StatusbarUrlSuccessFgColor(template.ColorSettingValue): - - """Foreground color of the URL in the statusbar on successful load.""" - - default = "lime" - - -class StatusbarUrlErrorFgColor(template.ColorSettingValue): - - """Foreground color of the URL in the statusbar on error.""" - - default = "orange" - - -class StatusbarUrlWarnFgColor(template.ColorSettingValue): - - """Foreground color of the URL in the statusbar when there's a warning.""" - - default = "yellow" - - -class StatusbarUrlHoverFgColor(template.ColorSettingValue): - - """Foreground color of the URL in the statusbar for hovered links.""" - - default = "aqua" - - -class TabFgColor(template.ColorSettingValue): - - """Foreground color of the tabbar.""" - - default = "white" - - -class TabBgColor(template.ColorSettingValue): - - """Background color of the tabbar.""" - - default = "grey" - - -class TabSelectedBgColor(template.ColorSettingValue): - - """Background color of the tabbar for the selected tab.""" - - default = "black" - - -class TabSeperatorColor(template.ColorSettingValue): - - """Color for the tab seperator.""" - - default = "white" - - -class MonospaceFonts(template.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(template.FontSettingValue): - - """Font used in the completion widget.""" - - default = "8pt " + MonospaceFonts.default - default_conf = "8pt ${_monospace}" - - -class TabbarFont(template.FontSettingValue): - - """Font used in the tabbar.""" - - default = "8pt " + MonospaceFonts.default - default_conf = "8pt ${_monospace}" - - -class StatusbarFont(template.FontSettingValue): - - """Font used in the statusbar.""" - - default = "8pt " + MonospaceFonts.default - default_conf = "8pt ${_monospace}" - - -class SearchEngineName(template.SettingValue): - - """A search engine name.""" - - def validate(self): - return True - - -class SearchEngineUrl(template.SettingValue): - - """A search engine URL.""" - - def validate(self): - return "{}" in self.value - - -class KeyBindingName(template.SettingValue): - - """The name (keys) of a keybinding.""" - - def validate(self): - # FIXME can we validate anything here? - return True - - -class KeyBinding(template.CommandSettingValue): - - """The command of a keybinding.""" - - pass diff --git a/qutebrowser/config/sections.py b/qutebrowser/config/sections.py index fa975d617..5f8f46204 100644 --- a/qutebrowser/config/sections.py +++ b/qutebrowser/config/sections.py @@ -20,7 +20,7 @@ from collections import OrderedDict import qutebrowser.config.templates as template -import qutebrowser.config.options as opt +import qutebrowser.config.conftypes as conftypes class KeyValue: @@ -47,7 +47,9 @@ class KeyValue: """ if args: - self.values = OrderedDict(args) + self.values = OrderedDict() + for (k, settingval, desc) in args: + self.values[k] = settingval def __getitem__(self, key): """Get the value for key. @@ -89,7 +91,7 @@ class SearchEngines(template.ValueListSection): """Search engine config section.""" - types = (opt.SearchEngineName, opt.SearchEngineUrl) + types = (conftypes.SearchEngineName, conftypes.SearchEngineUrl) # FIXME how to handle interpolation here? default = OrderedDict([ ('DEFAULT', '${duckduckgo}'), @@ -107,7 +109,7 @@ class KeyBindings(template.ValueListSection): """Keybindings config section.""" - types = (opt.KeyBindingName, opt.KeyBinding) + types = (conftypes.KeyBindingName, conftypes.KeyBinding) default = OrderedDict([ ('o', 'open'), ('go', 'opencur'), @@ -153,5 +155,5 @@ class Aliases(template.ValueListSection): """Aliases config section.""" - types = (template.CommandSettingValue, template.CommandSettingValue) + types = (conftypes.Command, conftypes.Command) default = OrderedDict() diff --git a/qutebrowser/config/templates.py b/qutebrowser/config/templates.py index 89ef1d882..fc44dd914 100644 --- a/qutebrowser/config/templates.py +++ b/qutebrowser/config/templates.py @@ -19,8 +19,6 @@ from collections import OrderedDict -import qutebrowser.commands.utils as cmdutils - class SettingValue: @@ -29,35 +27,27 @@ class SettingValue: Intended to be subclassed by config value "types". Attributes: - valid_values: Possible values if they can be expressed as a fixed - string. Either a list of strings, or a list of (value, - desc) tuples. - # FIXME actually handle tuples and stuff when validating - + typ: A BaseType subclass. default: Default value if the user has not overridden it, as a string. default_conf: Default value for the config, with interpolation. value: (property) The currently valid, most important, transformed value. rawvalue: The current value as a raw string. - typestr: The name of the type to appear in the config. """ - valid_values = None - default = None - default_conf = None - typestr = None - rawvalue = None - - def __init__(self, rawval=None): + def __init__(self, typ, default, default_conf=None): """Constructor. Args: - rawval: Raw value to set. + typ: The BaseType to use. + default: Raw value to set. + default_conf: Raw value to set, for the config. """ - if rawval is not None: - self.rawvalue = rawval + self.typ = typ + self.default = default + self.default_conf = default_conf def __str__(self): """Get raw string value.""" @@ -74,160 +64,7 @@ class SettingValue: val = self.rawvalue else: val = self.default - return self.transform(val) - - 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. - - Return: - The transformed value. - - """ - return value - - def validate(self): - """Validate value against possible values. - - The default implementation checks the value against self.valid_values - if it was defined. - - Return: - Ture if validation succeeded, False otherwise. - - Raise: - NotImplementedError if self.valid_values is not defined and this - method should be overridden. - - """ - if self.valid_values is not None: - return self.value in self.valid_values - else: - raise NotImplementedError - - -class StringSettingValue(SettingValue): - - """Base class for a string setting (case-insensitive).""" - - typestr = 'string' - - def transform(self, value): - return value.lower() - - -class BoolSettingValue(SettingValue): - - """Base class for a boolean setting.""" - - valid_values = ['true', 'false'] - typestr = 'bool' - - # 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): - return self.value.lower() in self._BOOLEAN_STATES - - -class IntSettingValue(SettingValue): - - """Base class for an integer setting.""" - - typestr = 'int' - - def transform(self, value): - return int(value) - - def validate(self): - try: - int(self.value) - except ValueError: - return False - else: - return True - - -class ListSettingValue(SettingValue): - - """Base class for a (string-)list setting.""" - - typestr = 'string-list' - - def transform(self, value): - return value.split(',') - - def validate(self): - return True - - -class IntListSettingValue(ListSettingValue): - - """Base class for an int-list setting.""" - - typestr = 'int-list' - - def transform(self, value): - vals = super().transform(value) - return map(int, vals) - - def validate(self): - try: - self.transform(self.value) - except ValueError: - return False - else: - return True - - -class CommandSettingValue(SettingValue): - - """Base class for a command value with arguments.""" - - typestr = 'command' - - valid_values = cmdutils.cmd_dict.items() - - def validate(self): - # We need to import this here to avoid circular dependencies - from qutebrowser.commands.parsers import (CommandParser, - NoSuchCommandError) - cp = CommandParser() - try: - cp.parse(self.value) - except NoSuchCommandError: - return False - else: - return True - - -class ColorSettingValue(SettingValue): - - """Base class for a color value.""" - - typestr = 'color' - - def validate(self): - # FIXME validate colors - return True - - -class FontSettingValue(SettingValue): - - """Base class for a font value.""" - - typestr = 'font' - - def validate(self): - # FIXME validate fonts - return True + return self.typ.transform(val) class ValueListSection: @@ -255,7 +92,9 @@ class ValueListSection: def __init__(self): """Wrap types over default values. Take care when overriding this.""" self.values = OrderedDict() - self.default = {self.types[0](key): self.types[1](value) + keytype = self.types[0]() + valtype = self.types[1]() + self.default = {keytype.transform(key): valtype.transform(value) for key, value in self.default.items()} def __getitem__(self, key):