Don't make default config a mutable global.

Before, configdata.DATA only existed once - that means when something
manipulated it, instantiating a new ConfigManager actually gave us the
*modified* rather than the default data.

There's still a (now readonly) configdata.DATA for performance reasons -
before, the settings completion model called data() many times, which caused
initializing of it taking a few (instead of nearly 0) seconds.

See https://github.com/hackebrot/qutebrowser/pull/16#discussion-diff-27770433
This commit is contained in:
Florian Bruhin 2015-04-04 21:20:26 +02:00
parent b2df5a5b47
commit 57158e7191
3 changed files with 898 additions and 833 deletions

View File

@ -281,7 +281,7 @@ class ConfigManager(QObject):
def __init__(self, configdir, fname, relaxed=False, parent=None): def __init__(self, configdir, fname, relaxed=False, parent=None):
super().__init__(parent) super().__init__(parent)
self._initialized = False self._initialized = False
self.sections = configdata.DATA self.sections = configdata.data()
self._interpolation = configparser.ExtendedInterpolation() self._interpolation = configparser.ExtendedInterpolation()
self._proxies = {} self._proxies = {}
for sectname in self.sections.keys(): for sectname in self.sections.keys():

View File

@ -23,7 +23,8 @@ Module attributes:
FIRST_COMMENT: The initial comment header to place in the config. FIRST_COMMENT: The initial comment header to place in the config.
SECTION_DESC: A dictionary with descriptions for sections. SECTION_DESC: A dictionary with descriptions for sections.
DATA: The config defaults, an OrderedDict of sections. DATA: A global read-only copy of the default config, an OrderedDict of
sections.
""" """
import sys import sys
@ -117,7 +118,13 @@ SECTION_DESC = {
DEFAULT_FONT_SIZE = '10pt' if sys.platform == 'darwin' else '8pt' DEFAULT_FONT_SIZE = '10pt' if sys.platform == 'darwin' else '8pt'
DATA = collections.OrderedDict([ def data(readonly=False):
"""Get the default config data.
Return:
A {name: section} OrderedDict.
"""
return collections.OrderedDict([
('general', sect.KeyValue( ('general', sect.KeyValue(
('ignore-case', ('ignore-case',
SettingValue(typ.IgnoreCase(), 'smart'), SettingValue(typ.IgnoreCase(), 'smart'),
@ -125,7 +132,8 @@ DATA = collections.OrderedDict([
('wrap-search', ('wrap-search',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to wrap finding text to the top when arriving at the end."), "Whether to wrap finding text to the top when arriving at the "
"end."),
('startpage', ('startpage',
SettingValue(typ.List(), 'https://www.duckduckgo.com'), SettingValue(typ.List(), 'https://www.duckduckgo.com'),
@ -151,9 +159,10 @@ DATA = collections.OrderedDict([
('editor', ('editor',
SettingValue(typ.ShellCommand(placeholder=True), 'gvim -f "{}"'), SettingValue(typ.ShellCommand(placeholder=True), 'gvim -f "{}"'),
"The editor (and arguments) to use for the `open-editor` command.\n\n" "The editor (and arguments) to use for the `open-editor` "
"Use `{}` for the filename. The value gets split like in a shell, so " "command.\n\n"
"you can use `\"` or `'` to quote arguments."), "Use `{}` for the filename. The value gets split like in a "
"shell, so you can use `\"` or `'` to quote arguments."),
('editor-encoding', ('editor-encoding',
SettingValue(typ.Encoding(), 'utf-8'), SettingValue(typ.Encoding(), 'utf-8'),
@ -167,8 +176,8 @@ DATA = collections.OrderedDict([
('developer-extras', ('developer-extras',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Enable extra tools for Web developers.\n\n" "Enable extra tools for Web developers.\n\n"
"This needs to be enabled for `:inspector` to work and also adds an " "This needs to be enabled for `:inspector` to work and also adds "
"_Inspect_ entry to the context menu."), "an _Inspect_ entry to the context menu."),
('print-element-backgrounds', ('print-element-backgrounds',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
@ -177,11 +186,11 @@ DATA = collections.OrderedDict([
('xss-auditing', ('xss-auditing',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether load requests should be monitored for cross-site scripting " "Whether load requests should be monitored for cross-site "
"attempts.\n\n" "scripting attempts.\n\n"
"Suspicious scripts will be blocked and reported in the inspector's " "Suspicious scripts will be blocked and reported in the "
"JavaScript console. Enabling this feature might have an impact on " "inspector's JavaScript console. Enabling this feature might "
"performance."), "have an impact on performance."),
('site-specific-quirks', ('site-specific-quirks',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
@ -191,8 +200,8 @@ DATA = collections.OrderedDict([
SettingValue(typ.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Default encoding to use for websites.\n\n" "Default encoding to use for websites.\n\n"
"The encoding must be a string describing an encoding such as " "The encoding must be a string describing an encoding such as "
'_utf-8_, _iso-8859-1_, etc. If left empty a default value will be ' "_utf-8_, _iso-8859-1_, etc. If left empty a default value will "
"used."), "be used."),
('new-instance-open-target', ('new-instance-open-target',
SettingValue(typ.NewInstanceOpenTarget(), 'window'), SettingValue(typ.NewInstanceOpenTarget(), 'window'),
@ -206,13 +215,15 @@ DATA = collections.OrderedDict([
('save-session', ('save-session',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to always save the open pages."), "Whether to always save the open pages."),
readonly=readonly
)), )),
('ui', sect.KeyValue( ('ui', sect.KeyValue(
('zoom-levels', ('zoom-levels',
SettingValue(typ.PercList(minval=0), SettingValue(typ.PercList(minval=0),
'25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,' '25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,'
'250%,300%,400%,500%'), '200%,250%,300%,400%,500%'),
"The available zoom levels, separated by commas."), "The available zoom levels, separated by commas."),
('default-zoom', ('default-zoom',
@ -237,13 +248,14 @@ DATA = collections.OrderedDict([
('zoom-text-only', ('zoom-text-only',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether the zoom factor on a frame applies only to the text or to " "Whether the zoom factor on a frame applies only to the text or "
"all content."), "to all content."),
('frame-flattening', ('frame-flattening',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to expand each subframe to its contents.\n\n" "Whether to expand each subframe to its contents.\n\n"
"This will flatten all the frames to become one scrollable page."), "This will flatten all the frames to become one scrollable "
"page."),
('user-stylesheet', ('user-stylesheet',
SettingValue(typ.UserStyleSheet(), SettingValue(typ.UserStyleSheet(),
@ -267,14 +279,16 @@ DATA = collections.OrderedDict([
SettingValue(typ.FormatString(fields=['perc', 'perc_raw', 'title', SettingValue(typ.FormatString(fields=['perc', 'perc_raw', 'title',
'title_sep', 'id']), 'title_sep', 'id']),
'{perc}{title}{title_sep}qutebrowser'), '{perc}{title}{title_sep}qutebrowser'),
"The format to use for the window title. The following placeholders " "The format to use for the window title. The following "
"are defined:\n\n" "placeholders are defined:\n\n"
"* `{perc}`: The percentage as a string like `[10%]`.\n" "* `{perc}`: The percentage as a string like `[10%]`.\n"
"* `{perc_raw}`: The raw percentage, e.g. `10`\n" "* `{perc_raw}`: The raw percentage, e.g. `10`\n"
"* `{title}`: The title of the current web page\n" "* `{title}`: The title of the current web page\n"
"* `{title_sep}`: The string ` - ` if a title is set, empty " "* `{title_sep}`: The string ` - ` if a title is set, empty "
"otherwise.\n" "otherwise.\n"
"* `{id}`: The internal window ID of this window."), "* `{id}`: The internal window ID of this window."),
readonly=readonly
)), )),
('network', sect.KeyValue( ('network', sect.KeyValue(
@ -293,8 +307,8 @@ DATA = collections.OrderedDict([
('proxy', ('proxy',
SettingValue(typ.Proxy(), 'system'), SettingValue(typ.Proxy(), 'system'),
"The proxy to use.\n\n" "The proxy to use.\n\n"
"In addition to the listed values, you can use a `socks://...` or " "In addition to the listed values, you can use a `socks://...` "
"`http://...` URL."), "or `http://...` URL."),
('proxy-dns-requests', ('proxy-dns-requests',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
@ -307,6 +321,8 @@ DATA = collections.OrderedDict([
('dns-prefetch', ('dns-prefetch',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to try to pre-fetch DNS entries to speed up browsing."), "Whether to try to pre-fetch DNS entries to speed up browsing."),
readonly=readonly
)), )),
('completion', sect.KeyValue( ('completion', sect.KeyValue(
@ -323,7 +339,8 @@ DATA = collections.OrderedDict([
"Whether to show the autocompletion window."), "Whether to show the autocompletion window."),
('height', ('height',
SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1), '50%'), SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1),
'50%'),
"The height of the completion, in px or as percentage of the " "The height of the completion, in px or as percentage of the "
"window."), "window."),
@ -339,13 +356,15 @@ DATA = collections.OrderedDict([
('quick-complete', ('quick-complete',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to move on to the next part when there's only one possible " "Whether to move on to the next part when there's only one "
"completion left."), "possible completion left."),
('shrink', ('shrink',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to shrink the completion to be smaller than the configured " "Whether to shrink the completion to be smaller than the "
"size if there are no scrollbars."), "configured size if there are no scrollbars."),
readonly=readonly
)), )),
('input', sect.KeyValue( ('input', sect.KeyValue(
@ -364,12 +383,13 @@ DATA = collections.OrderedDict([
('auto-leave-insert-mode', ('auto-leave-insert-mode',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to leave insert mode if a non-editable element is clicked."), "Whether to leave insert mode if a non-editable element is "
"clicked."),
('auto-insert-mode', ('auto-insert-mode',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to automatically enter insert mode if an editable element " "Whether to automatically enter insert mode if an editable "
"is focused after page load."), "element is focused after page load."),
('forward-unbound-keys', ('forward-unbound-keys',
SettingValue(typ.ForwardUnboundKeys(), 'auto'), SettingValue(typ.ForwardUnboundKeys(), 'auto'),
@ -382,28 +402,32 @@ DATA = collections.OrderedDict([
"focusable elements in a Web page, such as hyperlinks and form " "focusable elements in a Web page, such as hyperlinks and form "
"controls, by using Left, Right, Up and Down arrow keys. For " "controls, by using Left, Right, Up and Down arrow keys. For "
"example, if a user presses the Right key, heuristics determine " "example, if a user presses the Right key, heuristics determine "
"whether there is an element he might be trying to reach towards the " "whether there is an element he might be trying to reach towards "
"right and which element he probably wants."), "the right and which element he probably wants."),
('links-included-in-focus-chain', ('links-included-in-focus-chain',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether hyperlinks should be included in the keyboard focus chain."), "Whether hyperlinks should be included in the keyboard focus "
"chain."),
('rocker-gestures', ('rocker-gestures',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to enable Opera-like mouse rocker gestures. This disables " "Whether to enable Opera-like mouse rocker gestures. This "
"the context menu."), "disables the context menu."),
('mouse-zoom-divider', ('mouse-zoom-divider',
SettingValue(typ.Int(minval=1), '512'), SettingValue(typ.Int(minval=1), '512'),
"How much to divide the mouse wheel movements to translate them " "How much to divide the mouse wheel movements to translate them "
"into zoom increments."), "into zoom increments."),
readonly=readonly
)), )),
('tabs', sect.KeyValue( ('tabs', sect.KeyValue(
('background-tabs', ('background-tabs',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to open new tabs (middleclick/ctrl+click) in background."), "Whether to open new tabs (middleclick/ctrl+click) in "
"background."),
('select-on-remove', ('select-on-remove',
SettingValue(typ.SelectOnRemove(), 'right'), SettingValue(typ.SelectOnRemove(), 'right'),
@ -450,9 +474,10 @@ DATA = collections.OrderedDict([
"Whether to show favicons in the tab bar."), "Whether to show favicons in the tab bar."),
('width', ('width',
SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1), '20%'), SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1),
"The width of the tab bar if it's vertical, in px or as percentage " '20%'),
"of the window."), "The width of the tab bar if it's vertical, in px or as "
"percentage of the window."),
('indicator-width', ('indicator-width',
SettingValue(typ.Int(minval=0), '3'), SettingValue(typ.Int(minval=0), '3'),
@ -467,9 +492,9 @@ DATA = collections.OrderedDict([
"Whether to open windows instead of tabs."), "Whether to open windows instead of tabs."),
('title-format', ('title-format',
SettingValue(typ.FormatString(fields=['perc', 'perc_raw', 'title', SettingValue(typ.FormatString(
'title_sep', 'index', 'id']), fields=['perc', 'perc_raw', 'title', 'title_sep', 'index',
'{index}: {title}'), 'id']), '{index}: {title}'),
"The format to use for the tab title. The following placeholders " "The format to use for the tab title. The following placeholders "
"are defined:\n\n" "are defined:\n\n"
"* `{perc}`: The percentage as a string like `[10%]`.\n" "* `{perc}`: The percentage as a string like `[10%]`.\n"
@ -479,33 +504,36 @@ DATA = collections.OrderedDict([
"otherwise.\n" "otherwise.\n"
"* `{index}`: The index of this tab.\n" "* `{index}`: The index of this tab.\n"
"* `{id}`: The internal tab ID of this tab."), "* `{id}`: The internal tab ID of this tab."),
readonly=readonly
)), )),
('storage', sect.KeyValue( ('storage', sect.KeyValue(
('download-directory', ('download-directory',
SettingValue(typ.Directory(none_ok=True), ''), SettingValue(typ.Directory(none_ok=True), ''),
"The directory to save downloads to. An empty value selects a " "The directory to save downloads to. An empty value selects a "
"sensible os-specific default. Will expand environment variables."), "sensible os-specific default. Will expand environment "
"variables."),
('maximum-pages-in-cache', ('maximum-pages-in-cache',
SettingValue( SettingValue(
typ.Int(none_ok=True, minval=0, maxval=MAXVALS['int']), ''), typ.Int(none_ok=True, minval=0, maxval=MAXVALS['int']), ''),
"The maximum number of pages to hold in the global memory page " "The maximum number of pages to hold in the global memory page "
"cache.\n\n" "cache.\n\n"
"The Page Cache allows for a nicer user experience when navigating " "The Page Cache allows for a nicer user experience when "
"forth or back to pages in the forward/back history, by pausing and " "navigating forth or back to pages in the forward/back history, "
"resuming up to _n_ pages.\n\n" "by pausing and resuming up to _n_ pages.\n\n"
"For more information about the feature, please refer to: " "For more information about the feature, please refer to: "
"http://webkit.org/blog/427/webkit-page-cache-i-the-basics/"), "http://webkit.org/blog/427/webkit-page-cache-i-the-basics/"),
('object-cache-capacities', ('object-cache-capacities',
SettingValue( SettingValue(
typ.WebKitBytesList(length=3, maxsize=MAXVALS['int']), ''), typ.WebKitBytesList(length=3, maxsize=MAXVALS['int']), ''),
"The capacities for the global memory cache for dead objects such as " "The capacities for the global memory cache for dead objects "
"stylesheets or scripts. Syntax: cacheMinDeadCapacity, cacheMaxDead, " "such as stylesheets or scripts. Syntax: cacheMinDeadCapacity, "
"totalCapacity.\n\n" "cacheMaxDead, totalCapacity.\n\n"
"The _cacheMinDeadCapacity_ specifies the minimum number of bytes " "The _cacheMinDeadCapacity_ specifies the minimum number of "
"that dead objects should consume when the cache is under " "bytes that dead objects should consume when the cache is under "
"pressure.\n\n" "pressure.\n\n"
"_cacheMaxDead_ is the maximum number of bytes that dead objects " "_cacheMaxDead_ is the maximum number of bytes that dead objects "
"should consume when the cache is *not* under pressure.\n\n" "should consume when the cache is *not* under pressure.\n\n"
@ -522,26 +550,31 @@ DATA = collections.OrderedDict([
('offline-storage-database', ('offline-storage-database',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 offline storage feature is enabled."), "Whether support for the HTML 5 offline storage feature is "
"enabled."),
('offline-web-application-storage', ('offline-web-application-storage',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 web application cache feature is " "Whether support for the HTML 5 web application cache feature is "
"enabled.\n\n" "enabled.\n\n"
"An application cache acts like an HTTP cache in some sense. For " "An application cache acts like an HTTP cache in some sense. For "
"documents that use the application cache via JavaScript, the loader " "documents that use the application cache via JavaScript, the "
"engine will first ask the application cache for the contents, " "loader engine will first ask the application cache for the "
"before hitting the network.\n\n" "contents, before hitting the network.\n\n"
"The feature is described in details at: " "The feature is described in details at: "
"http://dev.w3.org/html5/spec/Overview.html#appcache"), "http://dev.w3.org/html5/spec/Overview.html#appcache"),
('local-storage', ('local-storage',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 local storage feature is enabled."), "Whether support for the HTML 5 local storage feature is "
"enabled."),
('cache-size', ('cache-size',
SettingValue(typ.Int(minval=0, maxval=MAXVALS['int64']), '52428800'), SettingValue(typ.Int(minval=0, maxval=MAXVALS['int64']),
'52428800'),
"Size of the HTTP network cache."), "Size of the HTTP network cache."),
readonly=readonly
)), )),
('content', sect.KeyValue( ('content', sect.KeyValue(
@ -556,8 +589,8 @@ DATA = collections.OrderedDict([
('allow-plugins', ('allow-plugins',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Enables or disables plugins in Web pages.\n\n" "Enables or disables plugins in Web pages.\n\n"
'Qt plugins with a mimetype such as "application/x-qt-plugin" are ' 'Qt plugins with a mimetype such as "application/x-qt-plugin" '
"not affected by this setting."), "are not affected by this setting."),
('geolocation', ('geolocation',
SettingValue(typ.NoAsk(), 'ask'), SettingValue(typ.NoAsk(), 'ask'),
@ -582,7 +615,8 @@ DATA = collections.OrderedDict([
('javascript-can-access-clipboard', ('javascript-can-access-clipboard',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether JavaScript programs can read or write to the clipboard."), "Whether JavaScript programs can read or write to the "
"clipboard."),
('ignore-javascript-prompt', ('ignore-javascript-prompt',
SettingValue(typ.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
@ -599,8 +633,8 @@ DATA = collections.OrderedDict([
('local-content-can-access-file-urls', ('local-content-can-access-file-urls',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether locally loaded documents are allowed to access other local " "Whether locally loaded documents are allowed to access other "
"urls."), "local urls."),
('cookies-accept', ('cookies-accept',
SettingValue(typ.AcceptCookies(), 'default'), SettingValue(typ.AcceptCookies(), 'default'),
@ -611,7 +645,8 @@ DATA = collections.OrderedDict([
"Whether to store cookies."), "Whether to store cookies."),
('host-block-lists', ('host-block-lists',
SettingValue(typ.UrlList(none_ok=True), SettingValue(
typ.UrlList(none_ok=True),
'http://www.malwaredomainlist.com/hostslist/hosts.txt,' 'http://www.malwaredomainlist.com/hostslist/hosts.txt,'
'http://someonewhocares.org/hosts/hosts,' 'http://someonewhocares.org/hosts/hosts,'
'http://winhelp2002.mvps.org/hosts.zip,' 'http://winhelp2002.mvps.org/hosts.zip,'
@ -622,12 +657,14 @@ DATA = collections.OrderedDict([
"The file can be in one of the following formats:\n\n" "The file can be in one of the following formats:\n\n"
"- An '/etc/hosts'-like file\n" "- An '/etc/hosts'-like file\n"
"- One host per line\n" "- One host per line\n"
"- A zip-file of any of the above, with either only one file, or a " "- A zip-file of any of the above, with either only one file, or "
"file named 'hosts' (with any extension)."), "a file named 'hosts' (with any extension)."),
('host-blocking-enabled', ('host-blocking-enabled',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether host blocking is enabled."), "Whether host blocking is enabled."),
readonly=readonly
)), )),
('hints', sect.KeyValue( ('hints', sect.KeyValue(
@ -674,15 +711,21 @@ DATA = collections.OrderedDict([
r'\bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,' r'\bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,'
r'\b(<<|«)\b'), r'\b(<<|«)\b'),
"A comma-separated list of regexes to use for 'prev' links."), "A comma-separated list of regexes to use for 'prev' links."),
readonly=readonly
)), )),
('searchengines', sect.ValueList( ('searchengines', sect.ValueList(
typ.SearchEngineName(), typ.SearchEngineUrl(), typ.SearchEngineName(), typ.SearchEngineUrl(),
('DEFAULT', 'https://duckduckgo.com/?q={}'), ('DEFAULT', 'https://duckduckgo.com/?q={}'),
readonly=readonly
)), )),
('aliases', sect.ValueList( ('aliases', sect.ValueList(
typ.String(forbidden=' '), typ.Command(), typ.String(forbidden=' '), typ.Command(),
readonly=readonly
)), )),
('colors', sect.KeyValue( ('colors', sect.KeyValue(
@ -728,8 +771,8 @@ DATA = collections.OrderedDict([
"Top border color of the completion widget category headers."), "Top border color of the completion widget category headers."),
('completion.item.selected.border.bottom', ('completion.item.selected.border.bottom',
SettingValue(typ.QssColor(), '${completion.item.selected.border.' SettingValue(
'top}'), typ.QssColor(), '${completion.item.selected.border.top}'),
"Bottom border color of the selected completion item."), "Bottom border color of the selected completion item."),
('completion.match.fg', ('completion.match.fg',
@ -784,7 +827,8 @@ DATA = collections.OrderedDict([
('statusbar.url.fg.hover', ('statusbar.url.fg.hover',
SettingValue(typ.QssColor(), 'aqua'), SettingValue(typ.QssColor(), 'aqua'),
"Foreground color of the URL in the statusbar for hovered links."), "Foreground color of the URL in the statusbar for hovered "
"links."),
('tabs.fg.odd', ('tabs.fg.odd',
SettingValue(typ.QtColor(), 'white'), SettingValue(typ.QtColor(), 'white'),
@ -839,7 +883,8 @@ DATA = collections.OrderedDict([
"Font color for the matched part of hints."), "Font color for the matched part of hints."),
('hints.bg', ('hints.bg',
SettingValue(typ.CssColor(), '-webkit-gradient(linear, left top, ' SettingValue(
typ.CssColor(), '-webkit-gradient(linear, left top, '
'left bottom, color-stop(0%,#FFF785), ' 'left bottom, color-stop(0%,#FFF785), '
'color-stop(100%,#FFC542))'), 'color-stop(100%,#FFC542))'),
"Background color for hints."), "Background color for hints."),
@ -867,14 +912,17 @@ DATA = collections.OrderedDict([
('downloads.bg.error', ('downloads.bg.error',
SettingValue(typ.QtColor(), 'red'), SettingValue(typ.QtColor(), 'red'),
"Background color for downloads with errors."), "Background color for downloads with errors."),
readonly=readonly
)), )),
('fonts', sect.KeyValue( ('fonts', sect.KeyValue(
('_monospace', ('_monospace',
SettingValue(typ.Font(), 'Terminus, Monospace, "DejaVu Sans Mono", ' SettingValue(typ.Font(), 'Terminus, Monospace, '
'Monaco, "Bitstream Vera Sans Mono", "Andale Mono", ' '"DejaVu Sans Mono", Monaco, '
'"Liberation Mono", "Courier New", Courier, monospace, ' '"Bitstream Vera Sans Mono", "Andale Mono", '
'Fixed, Consolas, Terminal'), '"Liberation Mono", "Courier New", Courier, '
'monospace, Fixed, Consolas, Terminal'),
"Default monospace fonts."), "Default monospace fonts."),
('completion', ('completion',
@ -933,7 +981,8 @@ DATA = collections.OrderedDict([
('web-size-minimum-logical', ('web-size-minimum-logical',
SettingValue( SettingValue(
typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The minimum logical font size that is applied when zooming out."), "The minimum logical font size that is applied when zooming "
"out."),
('web-size-default', ('web-size-default',
SettingValue( SettingValue(
@ -944,8 +993,13 @@ DATA = collections.OrderedDict([
SettingValue( SettingValue(
typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The default font size for fixed-pitch text."), "The default font size for fixed-pitch text."),
readonly=readonly
)), )),
]) ])
DATA = data(readonly=True)
KEY_FIRST_COMMENT = """ KEY_FIRST_COMMENT = """

View File

@ -29,6 +29,7 @@ class Section:
"""Base class for KeyValue/ValueList sections. """Base class for KeyValue/ValueList sections.
Attributes: Attributes:
_readonly: Whether this section is read-only.
values: An OrderedDict with key as index and value as value. values: An OrderedDict with key as index and value as value.
key: string key: string
value: SettingValue value: SettingValue
@ -38,6 +39,7 @@ class Section:
def __init__(self): def __init__(self):
self.values = None self.values = None
self.descriptions = {} self.descriptions = {}
self._readonly = False
def __getitem__(self, key): def __getitem__(self, key):
"""Get the value for key. """Get the value for key.
@ -99,13 +101,15 @@ class KeyValue(Section):
set of keys. set of keys.
""" """
def __init__(self, *defaults): def __init__(self, *defaults, readonly=False):
"""Constructor. """Constructor.
Args: Args:
*defaults: A (key, value, description) list of defaults. *defaults: A (key, value, description) list of defaults.
readonly: Whether this config is readonly.
""" """
super().__init__() super().__init__()
self._readonly = readonly
if not defaults: if not defaults:
return return
self.values = collections.OrderedDict() self.values = collections.OrderedDict()
@ -115,6 +119,8 @@ class KeyValue(Section):
self.descriptions[k] = desc self.descriptions[k] = desc
def setv(self, layer, key, value, interpolated): def setv(self, layer, key, value, interpolated):
if self._readonly:
raise ValueError("Trying to modify a read-only config!")
self.values[key].setv(layer, value, interpolated) self.values[key].setv(layer, value, interpolated)
def dump_userconfig(self): def dump_userconfig(self):
@ -143,17 +149,20 @@ class ValueList(Section):
keytype: The type to use for the key (only used for validating) keytype: The type to use for the key (only used for validating)
valtype: The type to use for the value. valtype: The type to use for the value.
_ordered_value_cache: A ChainMap-like OrderedDict of all values. _ordered_value_cache: A ChainMap-like OrderedDict of all values.
_readonly: Whether this section is read-only.
""" """
def __init__(self, keytype, valtype, *defaults): def __init__(self, keytype, valtype, *defaults, readonly=False):
"""Wrap types over default values. Take care when overriding this. """Wrap types over default values. Take care when overriding this.
Args: Args:
keytype: The type instance to be used for keys. keytype: The type instance to be used for keys.
valtype: The type instance to be used for values. valtype: The type instance to be used for values.
*defaults: A (key, value) list of default values. *defaults: A (key, value) list of default values.
readonly: Whether this config is readonly.
""" """
super().__init__() super().__init__()
self._readonly = readonly
self._ordered_value_cache = None self._ordered_value_cache = None
self.keytype = keytype self.keytype = keytype
self.valtype = valtype self.valtype = valtype
@ -182,6 +191,8 @@ class ValueList(Section):
return self._ordered_value_cache return self._ordered_value_cache
def setv(self, layer, key, value, interpolated): def setv(self, layer, key, value, interpolated):
if self._readonly:
raise ValueError("Trying to modify a read-only config!")
self.keytype.validate(key) self.keytype.validate(key)
if key in self.layers[layer]: if key in self.layers[layer]:
self.layers[layer][key].setv(layer, value, interpolated) self.layers[layer][key].setv(layer, value, interpolated)