parent
8a60855b88
commit
34815f5cf8
@ -71,6 +71,8 @@ Changed
|
|||||||
* Yes/no prompts don't use keybindings from the `prompt` section anymore, they
|
* Yes/no prompts don't use keybindings from the `prompt` section anymore, they
|
||||||
have their own `yesno` section instead.
|
have their own `yesno` section instead.
|
||||||
* Trying to bind invalid keys now shows an error.
|
* Trying to bind invalid keys now shows an error.
|
||||||
|
* The `bindings.default` setting can now only be set in a `config.py`, and
|
||||||
|
existing values in `autoconfig.yml` are ignored.
|
||||||
- Improvements for GreaseMonkey support:
|
- Improvements for GreaseMonkey support:
|
||||||
* `@include` and `@exclude` now support regex matches. With QtWebEngine and Qt
|
* `@include` and `@exclude` now support regex matches. With QtWebEngine and Qt
|
||||||
5.8 and newer, Qt handles the matching, but similar functionality will be
|
5.8 and newer, Qt handles the matching, but similar functionality will be
|
||||||
|
@ -376,6 +376,8 @@ Default keybindings. If you want to add bindings, modify `bindings.commands` ins
|
|||||||
The main purpose of this setting is that you can set it to an empty dictionary if you want to load no default keybindings at all.
|
The main purpose of this setting is that you can set it to an empty dictionary if you want to load no default keybindings at all.
|
||||||
If you want to preserve default bindings (and get new bindings when there is an update), use `config.bind()` in `config.py` or the `:bind` command, and leave this setting alone.
|
If you want to preserve default bindings (and get new bindings when there is an update), use `config.bind()` in `config.py` or the `:bind` command, and leave this setting alone.
|
||||||
|
|
||||||
|
This setting can only be set in config.py.
|
||||||
|
|
||||||
Type: <<types,Dict>>
|
Type: <<types,Dict>>
|
||||||
|
|
||||||
Default:
|
Default:
|
||||||
|
@ -29,7 +29,8 @@ def option(*, info):
|
|||||||
"""A CompletionModel filled with settings and their descriptions."""
|
"""A CompletionModel filled with settings and their descriptions."""
|
||||||
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
|
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
|
||||||
options = ((opt.name, opt.description, info.config.get_str(opt.name))
|
options = ((opt.name, opt.description, info.config.get_str(opt.name))
|
||||||
for opt in configdata.DATA.values())
|
for opt in configdata.DATA.values()
|
||||||
|
if not opt.no_autoconfig)
|
||||||
model.add_category(listcategory.ListCategory("Options", options))
|
model.add_category(listcategory.ListCategory("Options", options))
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@ -286,6 +286,11 @@ class Config(QObject):
|
|||||||
log.config.debug("Config option changed: {} = {}".format(
|
log.config.debug("Config option changed: {} = {}".format(
|
||||||
opt.name, value))
|
opt.name, value))
|
||||||
|
|
||||||
|
def _check_yaml(self, opt, save_yaml):
|
||||||
|
"""Make sure the given option may be set in autoconfig.yml."""
|
||||||
|
if save_yaml and opt.no_autoconfig:
|
||||||
|
raise configexc.NoAutoconfigError(opt.name)
|
||||||
|
|
||||||
def read_yaml(self):
|
def read_yaml(self):
|
||||||
"""Read the YAML settings from self._yaml."""
|
"""Read the YAML settings from self._yaml."""
|
||||||
self._yaml.load()
|
self._yaml.load()
|
||||||
@ -383,7 +388,9 @@ class Config(QObject):
|
|||||||
|
|
||||||
If save_yaml=True is given, store the new value to YAML.
|
If save_yaml=True is given, store the new value to YAML.
|
||||||
"""
|
"""
|
||||||
self._set_value(self.get_opt(name), value, pattern=pattern)
|
opt = self.get_opt(name)
|
||||||
|
self._check_yaml(opt, save_yaml)
|
||||||
|
self._set_value(opt, value, pattern=pattern)
|
||||||
if save_yaml:
|
if save_yaml:
|
||||||
self._yaml.set_obj(name, value, pattern=pattern)
|
self._yaml.set_obj(name, value, pattern=pattern)
|
||||||
|
|
||||||
@ -393,6 +400,7 @@ class Config(QObject):
|
|||||||
If save_yaml=True is given, store the new value to YAML.
|
If save_yaml=True is given, store the new value to YAML.
|
||||||
"""
|
"""
|
||||||
opt = self.get_opt(name)
|
opt = self.get_opt(name)
|
||||||
|
self._check_yaml(opt, save_yaml)
|
||||||
converted = opt.typ.from_str(value)
|
converted = opt.typ.from_str(value)
|
||||||
log.config.debug("Setting {} (type {}) to {!r} (converted from {!r})"
|
log.config.debug("Setting {} (type {}) to {!r} (converted from {!r})"
|
||||||
.format(name, opt.typ.__class__.__name__, converted,
|
.format(name, opt.typ.__class__.__name__, converted,
|
||||||
@ -403,7 +411,8 @@ class Config(QObject):
|
|||||||
|
|
||||||
def unset(self, name, *, save_yaml=False, pattern=None):
|
def unset(self, name, *, save_yaml=False, pattern=None):
|
||||||
"""Set the given setting back to its default."""
|
"""Set the given setting back to its default."""
|
||||||
self.get_opt(name) # To check whether it exists
|
opt = self.get_opt(name)
|
||||||
|
self._check_yaml(opt, save_yaml)
|
||||||
changed = self._values[name].remove(pattern)
|
changed = self._values[name].remove(pattern)
|
||||||
if changed:
|
if changed:
|
||||||
self.changed.emit(name)
|
self.changed.emit(name)
|
||||||
|
@ -50,6 +50,7 @@ class Option:
|
|||||||
description = attr.ib()
|
description = attr.ib()
|
||||||
supports_pattern = attr.ib(default=False)
|
supports_pattern = attr.ib(default=False)
|
||||||
restart = attr.ib(default=False)
|
restart = attr.ib(default=False)
|
||||||
|
no_autoconfig = attr.ib(default=False)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
@ -199,7 +200,7 @@ def _read_yaml(yaml_data):
|
|||||||
data = utils.yaml_load(yaml_data)
|
data = utils.yaml_load(yaml_data)
|
||||||
|
|
||||||
keys = {'type', 'default', 'desc', 'backend', 'restart',
|
keys = {'type', 'default', 'desc', 'backend', 'restart',
|
||||||
'supports_pattern'}
|
'supports_pattern', 'no_autoconfig'}
|
||||||
|
|
||||||
for name, option in data.items():
|
for name, option in data.items():
|
||||||
if set(option.keys()) == {'renamed'}:
|
if set(option.keys()) == {'renamed'}:
|
||||||
@ -227,6 +228,7 @@ def _read_yaml(yaml_data):
|
|||||||
description=option['desc'],
|
description=option['desc'],
|
||||||
restart=option.get('restart', False),
|
restart=option.get('restart', False),
|
||||||
supports_pattern=option.get('supports_pattern', False),
|
supports_pattern=option.get('supports_pattern', False),
|
||||||
|
no_autoconfig=option.get('no_autoconfig', False),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Make sure no key shadows another.
|
# Make sure no key shadows another.
|
||||||
|
@ -2177,6 +2177,7 @@ bindings.key_mappings:
|
|||||||
`bindings.commands`), the mapping is ignored.
|
`bindings.commands`), the mapping is ignored.
|
||||||
|
|
||||||
bindings.default:
|
bindings.default:
|
||||||
|
no_autoconfig: true
|
||||||
default:
|
default:
|
||||||
normal:
|
normal:
|
||||||
<Escape>: clear-keychain ;; search ;; fullscreen --leave
|
<Escape>: clear-keychain ;; search ;; fullscreen --leave
|
||||||
|
@ -31,6 +31,15 @@ class Error(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NoAutoconfigError(Error):
|
||||||
|
|
||||||
|
"""Raised when this option can't be set in autoconfig.yml."""
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super().__init__("The {} setting can only be set in config.py!"
|
||||||
|
.format(name))
|
||||||
|
|
||||||
|
|
||||||
class BackendError(Error):
|
class BackendError(Error):
|
||||||
|
|
||||||
"""Raised when this setting is unavailable with the current backend."""
|
"""Raised when this setting is unavailable with the current backend."""
|
||||||
|
@ -262,6 +262,12 @@ class YamlConfig(QObject):
|
|||||||
del settings[old]
|
del settings[old]
|
||||||
self._mark_changed()
|
self._mark_changed()
|
||||||
|
|
||||||
|
# bindings.default can't be set in autoconfig.yml anymore, so ignore
|
||||||
|
# old values.
|
||||||
|
if 'bindings.default' in settings:
|
||||||
|
del settings['bindings.default']
|
||||||
|
self._mark_changed()
|
||||||
|
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
def _validate(self, settings):
|
def _validate(self, settings):
|
||||||
|
@ -33,7 +33,7 @@ input { width: 98%; }
|
|||||||
<th>Setting</th>
|
<th>Setting</th>
|
||||||
<th>Value</th>
|
<th>Value</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for option in configdata.DATA.values() %}
|
{% for option in configdata.DATA.values() if not option.no_autoconfig %}
|
||||||
<tr>
|
<tr>
|
||||||
<!-- FIXME: convert to string properly -->
|
<!-- FIXME: convert to string properly -->
|
||||||
<td class="setting">{{ option.name }} (Current: {{ confget(option.name) | string |truncate(100) }})
|
<td class="setting">{{ option.name }} (Current: {{ confget(option.name) | string |truncate(100) }})
|
||||||
|
@ -421,6 +421,8 @@ def _generate_setting_option(f, opt):
|
|||||||
f.write("This setting requires a restart.\n")
|
f.write("This setting requires a restart.\n")
|
||||||
if opt.supports_pattern:
|
if opt.supports_pattern:
|
||||||
f.write("\nThis setting supports URL patterns.\n")
|
f.write("\nThis setting supports URL patterns.\n")
|
||||||
|
if opt.no_autoconfig:
|
||||||
|
f.write("\nThis setting can only be set in config.py.\n")
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
typ = opt.typ.get_name().replace(',', ',')
|
typ = opt.typ.get_name().replace(',', ',')
|
||||||
f.write('Type: <<types,{typ}>>\n'.format(typ=typ))
|
f.write('Type: <<types,{typ}>>\n'.format(typ=typ))
|
||||||
|
@ -111,7 +111,8 @@ def configdata_stub(config_stub, monkeypatch, configdata_init):
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
backends=[],
|
backends=[],
|
||||||
raw_backends=None)),
|
raw_backends=None,
|
||||||
|
no_autoconfig=True)),
|
||||||
('bindings.commands', configdata.Option(
|
('bindings.commands', configdata.Option(
|
||||||
name='bindings.commands',
|
name='bindings.commands',
|
||||||
description='Default keybindings',
|
description='Default keybindings',
|
||||||
@ -655,8 +656,6 @@ def test_setting_option_completion(qtmodeltester, config_stub,
|
|||||||
('bindings.commands', 'Default keybindings', (
|
('bindings.commands', 'Default keybindings', (
|
||||||
'{"normal": {"<Ctrl+q>": "quit", "ZQ": "quit", '
|
'{"normal": {"<Ctrl+q>": "quit", "ZQ": "quit", '
|
||||||
'"I": "invalid", "d": "scroll down"}}')),
|
'"I": "invalid", "d": "scroll down"}}')),
|
||||||
('bindings.default', 'Default keybindings',
|
|
||||||
'{"normal": {"<Ctrl+q>": "quit", "d": "tab-close"}}'),
|
|
||||||
('content.javascript.enabled', 'Enable/Disable JavaScript',
|
('content.javascript.enabled', 'Enable/Disable JavaScript',
|
||||||
'true'),
|
'true'),
|
||||||
]
|
]
|
||||||
|
@ -621,6 +621,34 @@ class TestConfig:
|
|||||||
meth('content.cookies.accept', 'all')
|
meth('content.cookies.accept', 'all')
|
||||||
assert not conf._values['content.cookies.accept']
|
assert not conf._values['content.cookies.accept']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('method, value', [
|
||||||
|
('set_obj', {}),
|
||||||
|
('set_str', '{}'),
|
||||||
|
])
|
||||||
|
def test_set_no_autoconfig_save(self, conf, qtbot, yaml_value,
|
||||||
|
method, value):
|
||||||
|
meth = getattr(conf, method)
|
||||||
|
option = 'bindings.default'
|
||||||
|
with pytest.raises(configexc.NoAutoconfigError):
|
||||||
|
with qtbot.assert_not_emitted(conf.changed):
|
||||||
|
meth(option, value, save_yaml=True)
|
||||||
|
|
||||||
|
assert not conf._values[option]
|
||||||
|
assert yaml_value(option) is configutils.UNSET
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('method, value', [
|
||||||
|
('set_obj', {}),
|
||||||
|
('set_str', '{}'),
|
||||||
|
])
|
||||||
|
def test_set_no_autoconfig_no_save(self, conf, qtbot, yaml_value,
|
||||||
|
method, value):
|
||||||
|
meth = getattr(conf, method)
|
||||||
|
option = 'bindings.default'
|
||||||
|
with qtbot.wait_signal(conf.changed):
|
||||||
|
meth(option, value)
|
||||||
|
|
||||||
|
assert conf._values[option]
|
||||||
|
|
||||||
@pytest.mark.parametrize('method', ['set_obj', 'set_str'])
|
@pytest.mark.parametrize('method', ['set_obj', 'set_str'])
|
||||||
def test_set_no_pattern(self, conf, method, qtbot):
|
def test_set_no_pattern(self, conf, method, qtbot):
|
||||||
meth = getattr(conf, method)
|
meth = getattr(conf, method)
|
||||||
|
@ -48,6 +48,12 @@ def test_no_option_error_clash():
|
|||||||
configexc.NoOptionError('opt', deleted=True, renamed='foo')
|
configexc.NoOptionError('opt', deleted=True, renamed='foo')
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_autoconfig_error():
|
||||||
|
e = configexc.NoAutoconfigError('opt')
|
||||||
|
expected = "The opt setting can only be set in config.py!"
|
||||||
|
assert str(e) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_backend_error():
|
def test_backend_error():
|
||||||
e = configexc.BackendError('foo', usertypes.Backend.QtWebKit)
|
e = configexc.BackendError('foo', usertypes.Backend.QtWebKit)
|
||||||
expected = "The foo setting is not available with the QtWebKit backend!"
|
expected = "The foo setting is not available with the QtWebKit backend!"
|
||||||
|
@ -223,6 +223,16 @@ class TestYaml:
|
|||||||
mode = 'persist' if persist else 'normal'
|
mode = 'persist' if persist else 'normal'
|
||||||
assert data['tabs.mode_on_change']['global'] == mode
|
assert data['tabs.mode_on_change']['global'] == mode
|
||||||
|
|
||||||
|
def test_bindings_default(self, yaml, autoconfig):
|
||||||
|
"""Make sure bindings.default gets removed from autoconfig.yml."""
|
||||||
|
autoconfig.write({'bindings.default': {'global': '{}'}})
|
||||||
|
|
||||||
|
yaml.load()
|
||||||
|
yaml._save()
|
||||||
|
|
||||||
|
data = autoconfig.read()
|
||||||
|
assert 'bindings.default' not in data
|
||||||
|
|
||||||
def test_renamed_key_unknown_target(self, monkeypatch, yaml,
|
def test_renamed_key_unknown_target(self, monkeypatch, yaml,
|
||||||
autoconfig):
|
autoconfig):
|
||||||
"""A key marked as renamed with invalid name should raise an error."""
|
"""A key marked as renamed with invalid name should raise an error."""
|
||||||
|
Loading…
Reference in New Issue
Block a user