From c703836794f1777b4d8c48f49866652dd15adb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Vinyals=20Valdepe=C3=B1as?= Date: Fri, 21 Oct 2022 22:45:10 +0200 Subject: [PATCH] feat(toggle-with-cycle): allows cycling option values at runtime --- helix-term/src/commands/typed.rs | 45 +++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 706442e45dcdd..186f23aeb9c0f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -8,7 +8,6 @@ use super::*; use helix_core::{encoding, shellwords::Shellwords}; use helix_view::document::DEFAULT_LANGUAGE_NAME; use helix_view::editor::{Action, CloseError, ConfigEvent}; -use serde_json::Value; use ui::completers::{self, Completer}; #[derive(Clone)] @@ -1790,8 +1789,8 @@ fn toggle_option( return Ok(()); } - if args.len() != 1 { - anyhow::bail!("Bad arguments. Usage: `:toggle key`"); + if args.is_empty() { + anyhow::bail!("Bad arguments. Usage: `:toggle key [values]?`"); } let key = &args[0].to_lowercase(); @@ -1801,22 +1800,44 @@ fn toggle_option( let pointer = format!("/{}", key.replace('.', "/")); let value = config.pointer_mut(&pointer).ok_or_else(key_error)?; - let Value::Bool(old_value) = *value else { - anyhow::bail!("Key `{}` is not toggle-able", key) + *value = match value.as_bool() { + Some(value) => serde_json::Value::Bool(!value), + None => { + if args.len() != 2 { + anyhow::bail!( + "Bad arguments. For non-boolean configurations use: `:toggle key val1,val2`" + ); + } + + // The comma separated values to cycle + let first_arg = &args[1]; + let field_error = |_| anyhow::anyhow!("Could not parse field `{}`", first_arg); + + if let Some(value) = value.as_str().and_then(|value| { + let mut entries = first_arg.split(',').peekable(); + let first = entries.peek().map(|first| first.to_owned()); + entries + .skip_while(|entry| entry != &value) + .nth(1) + .or(first) + .map(|value| serde_json::Value::String(value.to_string())) + }) { + value + } else { + first_arg.parse().map_err(field_error)? + } + } }; - let new_value = !old_value; - *value = Value::Bool(new_value); - // This unwrap should never fail because we only replace one boolean value - // with another, maintaining a valid json config - let config = serde_json::from_value(config).unwrap(); + let status = format!("Option `{}` is now set to `{}`", key, value); + let config = serde_json::from_value(config) + .map_err(|_| anyhow::anyhow!("Could not parse field: `{:?}`", &args))?; cx.editor .config_events .0 .send(ConfigEvent::Update(config))?; - cx.editor - .set_status(format!("Option `{}` is now set to `{}`", key, new_value)); + cx.editor.set_status(status); Ok(()) }