From d5707a4696af0c63ec350791501440e7d0adc036 Mon Sep 17 00:00:00 2001 From: Alex Vinyals Date: Mon, 5 Jun 2023 15:22:05 +0200 Subject: [PATCH] feat(commands): allows cycling option values at runtime (#4411) --- helix-term/src/commands/typed.rs | 49 ++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 706442e4..fb285e72 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,48 @@ 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) => { + ensure!( + args.len() == 1, + "Bad arguments. For boolean configurations use: `:toggle key`" + ); + serde_json::Value::Bool(!value) + } + None => { + ensure!( + args.len() > 2, + "Bad arguments. For non-boolean configurations use: `:toggle key val1 val2 ...`", + ); + ensure!( + value.is_string(), + "Bad configuration. Cannot cycle non-string configurations" + ); + + let value = value + .as_str() + .expect("programming error: should have been ensured before"); + + serde_json::Value::String( + args[1..] + .iter() + .skip_while(|e| *e != value) + .nth(1) + .unwrap_or_else(|| &args[1]) + .to_string(), + ) + } }; - 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!("'{key}' is now set to {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(()) }