diff --git a/crates/nuwiki-lsp/src/config.rs b/crates/nuwiki-lsp/src/config.rs index 8d36742..9871c15 100644 --- a/crates/nuwiki-lsp/src/config.rs +++ b/crates/nuwiki-lsp/src/config.rs @@ -389,6 +389,39 @@ impl Config { // ===== Wire schema ===== +/// Custom serde helper: accept JSON `true`/`false` **or** integers `0`/`1` +/// for `Option` fields. VimL dicts serialise `auto_export = 1` as +/// the JSON number `1`, not `true`, which would otherwise silently break +/// deserialisation of the entire `RawWiki` and cause the server to fall +/// back to `wiki_root` (ignoring the wikis list and marking every link +/// broken). +mod opt_bool_or_int { + use serde::{Deserialize, Deserializer}; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let v = Option::::deserialize(deserializer)?; + match v { + None | Some(serde_json::Value::Null) => Ok(None), + Some(serde_json::Value::Bool(b)) => Ok(Some(b)), + Some(serde_json::Value::Number(ref n)) => { + if let Some(i) = n.as_i64() { + Ok(Some(i != 0)) + } else { + Err(serde::de::Error::custom( + "expected bool or 0/1 integer for bool field", + )) + } + } + Some(other) => Err(serde::de::Error::custom(format!( + "expected bool or 0/1 integer, got {other}" + ))), + } + } +} + #[derive(Debug, Default, Deserialize)] #[serde(default, rename_all = "snake_case")] struct InitOptions { @@ -427,9 +460,9 @@ struct RawWiki { template_date_format: Option, #[serde(default)] css_name: Option, - #[serde(default)] + #[serde(default, deserialize_with = "opt_bool_or_int::deserialize")] auto_export: Option, - #[serde(default)] + #[serde(default, deserialize_with = "opt_bool_or_int::deserialize")] html_filename_parameterization: Option, #[serde(default)] exclude_files: Option>, @@ -453,7 +486,7 @@ struct RawWiki { maxhi: Option, #[serde(default)] listsyms: Option, - #[serde(default)] + #[serde(default, deserialize_with = "opt_bool_or_int::deserialize")] listsyms_propagate: Option, #[serde(default)] list_margin: Option, @@ -461,7 +494,7 @@ struct RawWiki { links_space_char: Option, #[serde(default)] nested_syntaxes: Option>, - #[serde(default)] + #[serde(default, deserialize_with = "opt_bool_or_int::deserialize")] auto_toc: Option, }