From 25c85836d68966368d63f0ac3e6749de0ed630a2 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 | 42 ++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 706442e45dcdd..6007969dc22b4 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,15 +1800,38 @@ 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) + let new_value = if let Some(old_value) = value.as_bool() { + serde_json::Value::Bool(!old_value) + } else { + 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(new_value) = value.as_str().and_then(|old_value| { + let mut entries = first_arg.split(',').peekable(); + let first = entries.peek().map(|e| e.to_owned()); + entries + .skip_while(|e| e != &old_value) + .nth(1) + .or(first) + .map(|new_value| serde_json::Value::String(new_value.to_string())) + }) { + new_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(); + *value = new_value.clone(); + + let config = serde_json::from_value(config) + .map_err(|_| anyhow::anyhow!("Could not parse field: `{:?}`", &args))?; cx.editor .config_events