Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Config.dump_userconfig return the same as config-write-py #4398

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 8 additions & 8 deletions qutebrowser/config/config.py
Expand Up @@ -461,15 +461,15 @@ def dump_userconfig(self):
Return:
The changed config part as string.
"""
blocks = []
for values in sorted(self, key=lambda v: v.opt.name):
if values:
blocks.append(str(values))

if not blocks:
return '<Default configuration>'
options = []
for values in self:
for scoped in values:
options.append((scoped.pattern, values.opt, scoped.value))
bindings = dict(self.get_mutable_obj('bindings.commands'))
generator = configutils.ConfigPyGenerator(options, bindings,
commented=False)

return '\n'.join(blocks)
return generator.gen_text()


class ConfigContainer:
Expand Down
17 changes: 6 additions & 11 deletions qutebrowser/config/configcommands.py
Expand Up @@ -433,18 +433,13 @@ def config_write_py(self, filename=None, force=False, defaults=False):
options = [(None, opt, opt.default)
for _name, opt in sorted(configdata.DATA.items())]
bindings = dict(configdata.DATA['bindings.default'].default)
commented = True
text = configutils.ConfigPyGenerator(options, bindings,
commented=True).gen_text()
else:
options = []
for values in self._config:
for scoped in values:
options.append((scoped.pattern, values.opt, scoped.value))
bindings = dict(self._config.get_mutable_obj('bindings.commands'))
commented = False

writer = configfiles.ConfigPyWriter(options, bindings,
commented=commented)
text = self._config.dump_userconfig()

try:
writer.write(filename)
with open(filename, 'w', encoding='utf-8') as f:
f.write(text)
except OSError as e:
raise cmdexc.CommandError(str(e))
101 changes: 0 additions & 101 deletions qutebrowser/config/configfiles.py
Expand Up @@ -426,107 +426,6 @@ def pattern(self, pattern):
yield container


class ConfigPyWriter:

"""Writer for config.py files from given settings."""

def __init__(self, options, bindings, *, commented):
self._options = options
self._bindings = bindings
self._commented = commented

def write(self, filename):
"""Write the config to the given file."""
with open(filename, 'w', encoding='utf-8') as f:
f.write('\n'.join(self._gen_lines()))

def _line(self, line):
"""Get an (optionally commented) line."""
if self._commented:
if line.startswith('#'):
return '#' + line
else:
return '# ' + line
else:
return line

def _gen_lines(self):
"""Generate a config.py with the given settings/bindings.

Yields individual lines.
"""
yield from self._gen_header()
yield from self._gen_options()
yield from self._gen_bindings()

def _gen_header(self):
"""Generate the initial header of the config."""
yield self._line("# Autogenerated config.py")
yield self._line("# Documentation:")
yield self._line("# qute://help/configuring.html")
yield self._line("# qute://help/settings.html")
yield ''
if self._commented:
# When generated from an autoconfig.yml with commented=False,
# we don't want to load that autoconfig.yml anymore.
yield self._line("# This is here so configs done via the GUI are "
"still loaded.")
yield self._line("# Remove it to not load settings done via the "
"GUI.")
yield self._line("config.load_autoconfig()")
yield ''
else:
yield self._line("# Uncomment this to still load settings "
"configured via autoconfig.yml")
yield self._line("# config.load_autoconfig()")
yield ''

def _gen_options(self):
"""Generate the options part of the config."""
for pattern, opt, value in self._options:
if opt.name in ['bindings.commands', 'bindings.default']:
continue

for line in textwrap.wrap(opt.description):
yield self._line("# {}".format(line))

yield self._line("# Type: {}".format(opt.typ.get_name()))

valid_values = opt.typ.get_valid_values()
if valid_values is not None and valid_values.generate_docs:
yield self._line("# Valid values:")
for val in valid_values:
try:
desc = valid_values.descriptions[val]
yield self._line("# - {}: {}".format(val, desc))
except KeyError:
yield self._line("# - {}".format(val))

if pattern is None:
yield self._line('c.{} = {!r}'.format(opt.name, value))
else:
yield self._line('config.set({!r}, {!r}, {!r})'.format(
opt.name, value, str(pattern)))
yield ''

def _gen_bindings(self):
"""Generate the bindings part of the config."""
normal_bindings = self._bindings.pop('normal', {})
if normal_bindings:
yield self._line('# Bindings for normal mode')
for key, command in sorted(normal_bindings.items()):
yield self._line('config.bind({!r}, {!r})'.format(
key, command))
yield ''

for mode, mode_bindings in sorted(self._bindings.items()):
yield self._line('# Bindings for {} mode'.format(mode))
for key, command in sorted(mode_bindings.items()):
yield self._line('config.bind({!r}, {!r}, mode={!r})'.format(
key, command, mode))
yield ''


def read_config_py(filename, raising=False):
"""Read a config.py file.

Expand Down
100 changes: 100 additions & 0 deletions qutebrowser/config/configutils.py
Expand Up @@ -22,6 +22,7 @@


import attr
import textwrap

from qutebrowser.utils import utils
from qutebrowser.config import configexc
Expand Down Expand Up @@ -184,3 +185,102 @@ def get_for_pattern(self, pattern, *, fallback=True):
return UNSET

return self._get_fallback(fallback)


class ConfigPyGenerator:

"""Generator of config.py-like strings from given settings."""

def __init__(self, options, bindings, *, commented):
self._options = options
self._bindings = bindings
self._commented = commented

def _line(self, line):
"""Get an (optionally commented) line."""
if self._commented:
if line.startswith('#'):
return '#' + line
else:
return '# ' + line
else:
return line

def gen_text(self):
return '\n'.join(self._gen_lines())

def _gen_lines(self):
"""Generate a config.py with the given settings/bindings.

Yields individual lines.
"""
yield from self._gen_header()
yield from self._gen_options()
yield from self._gen_bindings()

def _gen_header(self):
"""Generate the initial header of the config."""
yield self._line("# Autogenerated config.py")
yield self._line("# Documentation:")
yield self._line("# qute://help/configuring.html")
yield self._line("# qute://help/settings.html")
yield ''
if self._commented:
# When generated from an autoconfig.yml with commented=False,
# we don't want to load that autoconfig.yml anymore.
yield self._line("# This is here so configs done via the GUI are "
"still loaded.")
yield self._line("# Remove it to not load settings done via the "
"GUI.")
yield self._line("config.load_autoconfig()")
yield ''
else:
yield self._line("# Uncomment this to still load settings "
"configured via autoconfig.yml")
yield self._line("# config.load_autoconfig()")
yield ''

def _gen_options(self):
"""Generate the options part of the config."""
for pattern, opt, value in self._options:
if opt.name in ['bindings.commands', 'bindings.default']:
continue

for line in textwrap.wrap(opt.description):
yield self._line("# {}".format(line))

yield self._line("# Type: {}".format(opt.typ.get_name()))

valid_values = opt.typ.get_valid_values()
if valid_values is not None and valid_values.generate_docs:
yield self._line("# Valid values:")
for val in valid_values:
try:
desc = valid_values.descriptions[val]
yield self._line("# - {}: {}".format(val, desc))
except KeyError:
yield self._line("# - {}".format(val))

if pattern is None:
yield self._line('c.{} = {!r}'.format(opt.name, value))
else:
yield self._line('config.set({!r}, {!r}, {!r})'.format(
opt.name, value, str(pattern)))
yield ''

def _gen_bindings(self):
"""Generate the bindings part of the config."""
normal_bindings = self._bindings.pop('normal', {})
if normal_bindings:
yield self._line('# Bindings for normal mode')
for key, command in sorted(normal_bindings.items()):
yield self._line('config.bind({!r}, {!r})'.format(
key, command))
yield ''

for mode, mode_bindings in sorted(self._bindings.items()):
yield self._line('# Bindings for {} mode'.format(mode))
for key, command in sorted(mode_bindings.items()):
yield self._line('config.bind({!r}, {!r}, mode={!r})'.format(
key, command, mode))
yield ''