on master help sign in
feat(commands): allows cycling option values at runtime (#4411)
d5707a4Alex Vinyals
helix-term/src/commands/typed.rs+37−12
@@ -8,7 +8,6 @@ use super::*;
8use helix_core::{encoding, shellwords::Shellwords};
8use helix_core::{encoding, shellwords::Shellwords};
9use helix_view::document::DEFAULT_LANGUAGE_NAME;
9use helix_view::document::DEFAULT_LANGUAGE_NAME;
10use helix_view::editor::{Action, CloseError, ConfigEvent};
10use helix_view::editor::{Action, CloseError, ConfigEvent};
11−use serde_json::Value;
12use ui::completers::{self, Completer};
11use ui::completers::{self, Completer};
13
12
14#[derive(Clone)]
13#[derive(Clone)]
@@ -1790,8 +1789,8 @@ fn toggle_option(
1790 return Ok(());
1789 return Ok(());
1791 }
1790 }
1792
1791
1793− if args.len() != 1 {
1792+ if args.is_empty() {
1794− anyhow::bail!("Bad arguments. Usage: `:toggle key`");
1793+ anyhow::bail!("Bad arguments. Usage: `:toggle key [values]?`");
1795 }
1794 }
1796 let key = &args[0].to_lowercase();
1795 let key = &args[0].to_lowercase();
1797
1796
@@ -1801,22 +1800,48 @@ fn toggle_option(
1801 let pointer = format!("/{}", key.replace('.', "/"));
1800 let pointer = format!("/{}", key.replace('.', "/"));
1802 let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
1801 let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
1803
1802
1804− let Value::Bool(old_value) = *value else {
1803+ *value = match value.as_bool() {
1805− anyhow::bail!("Key `{}` is not toggle-able", key)
1804+ Some(value) => {
1805+ ensure!(
1806+ args.len() == 1,
1807+ "Bad arguments. For boolean configurations use: `:toggle key`"
1808+ );
1809+ serde_json::Value::Bool(!value)
1810+ }
1811+ None => {
1812+ ensure!(
1813+ args.len() > 2,
1814+ "Bad arguments. For non-boolean configurations use: `:toggle key val1 val2 ...`",
1815+ );
1816+ ensure!(
1817+ value.is_string(),
1818+ "Bad configuration. Cannot cycle non-string configurations"
1819+ );
1820+
1821+ let value = value
1822+ .as_str()
1823+ .expect("programming error: should have been ensured before");
1824+
1825+ serde_json::Value::String(
1826+ args[1..]
1827+ .iter()
1828+ .skip_while(|e| *e != value)
1829+ .nth(1)
1830+ .unwrap_or_else(|| &args[1])
1831+ .to_string(),
1832+ )
1833+ }
1806 };
1834 };
1807
1835
1808− let new_value = !old_value;
1836+ let status = format!("'{key}' is now set to {value}");
1809− *value = Value::Bool(new_value);
1810− // This unwrap should never fail because we only replace one boolean value
1811− // with another, maintaining a valid json config
1812− let config = serde_json::from_value(config).unwrap();
1837+ let config = serde_json::from_value(config)
1838+ .map_err(|_| anyhow::anyhow!("Could not parse field: `{:?}`", &args))?;
1813
1839
1814 cx.editor
1840 cx.editor
1815 .config_events
1841 .config_events
1816 .0
1842 .0
1817 .send(ConfigEvent::Update(config))?;
1843 .send(ConfigEvent::Update(config))?;
1818− cx.editor
1844+ cx.editor.set_status(status);
1819− .set_status(format!("Option `{}` is now set to `{}`", key, new_value));
1820 Ok(())
1845 Ok(())
1821}
1846}
1822
1847