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
- `: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
~~~~~~~~~~

View File

@ -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.

View File

@ -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?