Add --cycle flag to :set

Chooses the next value from the provided list of values (string-wise
comparison). Technically, the 'option!' syntax for toggling bools is now
redundant, but a translation from 'option!' to '--cycle option false
true' is kept for backwards compatibility.

The '--cycle' flag could also be technically optionally, since the only
thing that depends on it is preserving the error message for specifying
multiple values. (But I think it's best to keep it explicit, as a
principle-of-least-surprise thing)

Note: The business logic of picking the next value and setting it was
moved out to a separate function to avoid tripping pylint's
too-many-branches detector.

Fixes #47
This commit is contained in:
Niklas Haas 2016-08-11 04:31:42 +02:00 committed by Florian Bruhin
parent c57ad91e04
commit 1b5664b72f
3 changed files with 59 additions and 12 deletions

View File

@ -149,6 +149,7 @@ Changed
- `ui -> window-title-format` now has a new `{backend} ` replacement - `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 - `:hint` has a new `--add-history` argument to add the URL to the history for
yank/spawn targets. yank/spawn targets.
- `:set` now has a `--cycle` flag which lets you cycle through multiple options.
Deprecated Deprecated
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -772,13 +772,13 @@ class ConfigManager(QObject):
raise cmdexc.CommandError("set: {} - {}".format( raise cmdexc.CommandError("set: {} - {}".format(
e.__class__.__name__, e)) 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('section_', completion=Completion.section)
@cmdutils.argument('option', completion=Completion.option) @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) @cmdutils.argument('win_id', win_id=True)
def set_command(self, win_id, section_=None, option=None, value=None, def set_command(self, win_id, section_=None, option=None, *values,
temp=False, print_=False): temp=False, print_=False, cycle=False):
"""Set an option. """Set an option.
If the option name ends with '?', the value of the option is shown If the option name ends with '?', the value of the option is shown
@ -793,9 +793,10 @@ class ConfigManager(QObject):
Args: Args:
section_: The section where the option is in. section_: The section where the option is in.
option: The name of the option. 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. temp: Set value temporarily.
print_: Print the value after setting. print_: Print the value after setting.
cycle: Cycle through multiple provided values.
""" """
if section_ is not None and option is None: if section_ is not None and option is None:
raise cmdexc.CommandError( raise cmdexc.CommandError(
@ -812,27 +813,48 @@ class ConfigManager(QObject):
print_ = True print_ = True
else: else:
with self._handle_config_error(): 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] option = option[:-1]
val = self.get(section_, option) val = self.get(section_, option)
layer = 'temp' if temp else 'conf'
if isinstance(val, bool): if isinstance(val, bool):
self.set(layer, section_, option, str(not val).lower()) values = ['false', 'true']
else: else:
raise cmdexc.CommandError( raise cmdexc.CommandError(
"set: Attempted inversion of non-boolean value.") "set: Attempted inversion of non-boolean value.")
elif value is not None: elif not values:
layer = 'temp' if temp else 'conf'
self.set(layer, section_, option, value)
else:
raise cmdexc.CommandError("set: The following arguments " raise cmdexc.CommandError("set: The following arguments "
"are required: value") "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_: if print_:
with self._handle_config_error(): with self._handle_config_error():
val = self.get(section_, option, transformed=False) val = self.get(section_, option, transformed=False)
message.info("{} {} = {}".format(section_, option, val)) 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): def set(self, layer, sectname, optname, value, validate=True):
"""Set an option. """Set an option.

View File

@ -15,6 +15,10 @@ Feature: Setting settings.
When I run :set colors statusbar.bg When I run :set colors statusbar.bg
Then the error "set: The following arguments are required: value" should be shown 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 Scenario: Invalid section
When I run :set blah blub foo When I run :set blah blub foo
Then the error "set: Section 'blah' does not exist!" should be shown 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! When I run :set colors statusbar.bg!
Then the error "set: Attempted inversion of non-boolean value." should be shown 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 Scenario: Getting an option
When I run :set colors statusbar.bg magenta When I run :set colors statusbar.bg magenta
And I run :set colors statusbar.bg? And I run :set colors statusbar.bg?