on master help sign in
Refactor :set to parse by deserializing values (#1799)

* Refactor :set to parse by deserializing values * Implement serialize for idle_timeout config

commit2b0835b295bbf57a171210be967e039a1bddf823 authorGokul Soumya <gokulps15@gmail.com> dateTue 15 Mar 2022, 13:34 (5 years ago) parent0902ede
3 files changed+36−29
helix-core/src/syntax.rs+1−8 helix-term/src/commands/typed.rs+16−18 helix-view/src/editor.rs+19−3
helix-core/src/syntax.rs+1−8
@@ -216,14 +216,7 @@ impl FromStr for AutoPairConfig {
216216 // only do bool parsing for runtime setting
217217 fn from_str(s: &str) -> Result<Self, Self::Err> {
218218 let enable: bool = s.parse()?;
219−
220− let enable = if enable {
221− AutoPairConfig::Enable(true)
222− } else {
223− AutoPairConfig::Enable(false)
224− };
225−
226− Ok(enable)
219+ Ok(AutoPairConfig::Enable(enable))
227220 }
228221}
229222
helix-term/src/commands/typed.rs+16−18
@@ -872,34 +872,32 @@ pub(super) fn goto_line_number(
872872 Ok(())
873873}
874874
875+/// Change config at runtime. Access nested values by dot syntax, for
876+/// example to disable smart case search, use `:set search.smart-case false`.
875877fn setting(
876878 cx: &mut compositor::Context,
877879 args: &[Cow<str>],
878880 _event: PromptEvent,
879881) -> anyhow::Result<()> {
880− let runtime_config = &mut cx.editor.config;
881−
882882 if args.len() != 2 {
883883 anyhow::bail!("Bad arguments. Usage: `:set key field`");
884884 }
885−
886885 let (key, arg) = (&args[0].to_lowercase(), &args[1]);
887886
888− match key.as_ref() {
889− "scrolloff" => runtime_config.scrolloff = arg.parse()?,
890− "scroll-lines" => runtime_config.scroll_lines = arg.parse()?,
891− "mouse" => runtime_config.mouse = arg.parse()?,
892− "line-number" => runtime_config.line_number = arg.parse()?,
893− "middle-click_paste" => runtime_config.middle_click_paste = arg.parse()?,
894− "auto-pairs" => runtime_config.auto_pairs = arg.parse()?,
895− "auto-completion" => runtime_config.auto_completion = arg.parse()?,
896− "completion-trigger-len" => runtime_config.completion_trigger_len = arg.parse()?,
897− "auto-info" => runtime_config.auto_info = arg.parse()?,
898− "true-color" => runtime_config.true_color = arg.parse()?,
899− "search.smart-case" => runtime_config.search.smart_case = arg.parse()?,
900− "search.wrap-around" => runtime_config.search.wrap_around = arg.parse()?,
901− _ => anyhow::bail!("Unknown key `{}`.", args[0]),
902− }
887+ let key_error = || anyhow::anyhow!("Unknown key `{key}`");
888+ let field_error = |_| anyhow::anyhow!("Could not parse field `{arg}`");
889+
890+ let mut config = serde_json::to_value(&cx.editor.config).unwrap();
891+ let pointer = format!("/{}", key.replace('.', "/"));
892+ let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
893+
894+ *value = if value.is_string() {
895+ // JSON strings require quotes, so we can't .parse() directly
896+ serde_json::Value::String(arg.to_string())
897+ } else {
898+ arg.parse().map_err(field_error)?
899+ };
900+ cx.editor.config = serde_json::from_value(config).map_err(field_error)?;
903901
904902 Ok(())
905903}
helix-view/src/editor.rs+19−3
@@ -38,7 +38,7 @@ use helix_core::{
3838use helix_core::{Position, Selection};
3939use helix_dap as dap;
4040
41−use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize};
41+use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
4242
4343fn deserialize_duration_millis<'de, D>(deserializer: D) -> Result<Duration, D::Error>
4444where
@@ -48,6 +48,18 @@ where
4848 Ok(Duration::from_millis(millis))
4949}
5050
51+fn serialize_duration_millis<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
52+where
53+ S: Serializer,
54+{
55+ serializer.serialize_u64(
56+ duration
57+ .as_millis()
58+ .try_into()
59+ .map_err(|_| serde::ser::Error::custom("duration value overflowed u64"))?,
60+ )
61+}
62+
5163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5264#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
5365pub struct FilePickerConfig {
@@ -109,8 +121,12 @@ pub struct Config {
109121 pub auto_pairs: AutoPairConfig,
110122 /// Automatic auto-completion, automatically pop up without user trigger. Defaults to true.
111123 pub auto_completion: bool,
112− /// Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. Defaults to 400ms.
113− #[serde(skip_serializing, deserialize_with = "deserialize_duration_millis")]
124+ /// Time in milliseconds since last keypress before idle timers trigger.
125+ /// Used for autocompletion, set to 0 for instant. Defaults to 400ms.
126+ #[serde(
127+ serialize_with = "serialize_duration_millis",
128+ deserialize_with = "deserialize_duration_millis"
129+ )]
114130 pub idle_timeout: Duration,
115131 pub completion_trigger_len: u8,
116132 /// Whether to display infoboxes. Defaults to true.