diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index d0e412ced..4c3ebec9d 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -149,6 +149,7 @@ Changed - `ui -> window-title-format` now has a new `{backend} ` replacement - `:hint` has a new `--add-history` argument to add the URL to the history for yank/spawn targets. +- `:set` now has a `--cycle` flag which lets you cycle through multiple options. Deprecated ~~~~~~~~~~ diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index 57c498400..3bf559e66 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -772,13 +772,13 @@ class ConfigManager(QObject): raise cmdexc.CommandError("set: {} - {}".format( e.__class__.__name__, e)) - @cmdutils.register(name='set', instance='config') + @cmdutils.register(name='set', instance='config', star_args_optional=True) @cmdutils.argument('section_', completion=Completion.section) @cmdutils.argument('option', completion=Completion.option) - @cmdutils.argument('value', completion=Completion.value) + @cmdutils.argument('values', completion=Completion.value) @cmdutils.argument('win_id', win_id=True) - def set_command(self, win_id, section_=None, option=None, value=None, - temp=False, print_=False): + def set_command(self, win_id, section_=None, option=None, *values, + temp=False, print_=False, cycle=False): """Set an option. If the option name ends with '?', the value of the option is shown @@ -793,9 +793,10 @@ class ConfigManager(QObject): Args: section_: The section where the option is in. option: The name of the option. - value: The value to set. + values: The value to set, or the values to cycle through. temp: Set value temporarily. print_: Print the value after setting. + cycle: Cycle through multiple provided values. """ if section_ is not None and option is None: raise cmdexc.CommandError( @@ -812,27 +813,48 @@ class ConfigManager(QObject): print_ = True else: with self._handle_config_error(): - if option.endswith('!') and option != '!' and value is None: + if option.endswith('!') and option != '!' and not values: + # Handle inversion as special cases of the cycle code path option = option[:-1] val = self.get(section_, option) - layer = 'temp' if temp else 'conf' if isinstance(val, bool): - self.set(layer, section_, option, str(not val).lower()) + values = ['false', 'true'] else: raise cmdexc.CommandError( "set: Attempted inversion of non-boolean value.") - elif value is not None: - layer = 'temp' if temp else 'conf' - self.set(layer, section_, option, value) - else: + elif not values: raise cmdexc.CommandError("set: The following arguments " "are required: value") + elif not cycle and len(values) > 1: + raise cmdexc.CommandError("set: Too many values provided") + + layer = 'temp' if temp else 'conf' + self._set_next(layer, section_, option, values) if print_: with self._handle_config_error(): val = self.get(section_, option, transformed=False) message.info("{} {} = {}".format(section_, option, val)) + def _set_next(self, layer, section_, option, values): + """Set the next value out of a list of values.""" + if len(values) == 1: + # If we have only one value, just set it directly (avoid + # breaking stuff like aliases or other pseudo-settings) + self.set(layer, section_, option, values[0]) + else: + # Otherwise, use the next valid value from values, or the + # first if the current value does not appear in the list + assert len(values) > 1 + val = self.get(section_, option, transformed=False) + try: + idx = values.index(str(val)) + idx = (idx + 1) % len(values) + value = values[idx] + except ValueError: + value = values[0] + self.set(layer, section_, option, value) + def set(self, layer, sectname, optname, value, validate=True): """Set an option. diff --git a/tests/end2end/features/set.feature b/tests/end2end/features/set.feature index 1b1185a5c..76d92793b 100644 --- a/tests/end2end/features/set.feature +++ b/tests/end2end/features/set.feature @@ -15,6 +15,10 @@ Feature: Setting settings. When I run :set colors statusbar.bg Then the error "set: The following arguments are required: value" should be shown + Scenario: With too many values + When I run :set colors statusbar.bg green blue + Then the error "set: Too many values provided" should be shown + Scenario: Invalid section When I run :set blah blub foo Then the error "set: Section 'blah' does not exist!" should be shown @@ -32,6 +36,26 @@ Feature: Setting settings. When I run :set colors statusbar.bg! Then the error "set: Attempted inversion of non-boolean value." should be shown + Scenario: Cycling an option + When I run :set colors statusbar.bg magenta + And I run :set --cycle colors statusbar.bg green magenta blue yellow + Then colors -> statusbar.bg should be blue + + Scenario: Cycling an option through the end of the list + When I run :set colors statusbar.bg yellow + And I run :set --cycle colors statusbar.bg green magenta blue yellow + Then colors -> statusbar.bg should be green + + Scenario: Cycling an option that's not on the list + When I run :set colors statusbar.bg red + And I run :set --cycle colors statusbar.bg green magenta blue yellow + Then colors -> statusbar.bg should be green + + Scenario: Cycling through a single option + When I run :set colors statusbar.bg red + And I run :set --cycle colors statusbar.bg red + Then colors -> statusbar.bg should be red + Scenario: Getting an option When I run :set colors statusbar.bg magenta And I run :set colors statusbar.bg?