use std::collections::HashMap; use anyhow::bail; use helix_config::{options, List, Map, String, Ty, Value}; use crate::lsp; // TODO: differentiating between Some(null) and None is not really practical // since the distinction is lost on a roundtrip trough config::Value. // Porbably better to change our code to treat null the way we currently // treat None options! { struct LanguageServerConfig { /// The name or path of the language server binary to execute. Binaries must be in `$PATH` command: Option = None, /// A list of arguments to pass to the language server binary #[read = deref] args: List = List::default(), /// Any environment variables that will be used when starting the language server enviorment: Map = Map::default(), /// LSP initialization options #[name = "config"] server_config: Option> = None, /// LSP initialization options #[read = copy] timeout: u64 = 20, // TODO: merge /// LSP formatting options #[name = "config.format"] #[read = fold(HashMap::new(), fold_format_config, FormatConfig)] format: Map = Map::default() } } type FormatConfig = HashMap; fn fold_format_config(config: &Map, mut res: FormatConfig) -> FormatConfig { for (k, v) in config.iter() { res.entry(k.to_string()).or_insert_with(|| v.0.clone()); } res } // damm orphan rules :/ #[derive(Debug, PartialEq, Clone)] struct FormattingProperty(lsp::FormattingProperty); impl Ty for FormattingProperty { fn from_value(val: Value) -> anyhow::Result { match val { Value::Int(_) => Ok(FormattingProperty(lsp::FormattingProperty::Number( i32::from_value(val)?, ))), Value::Bool(val) => Ok(FormattingProperty(lsp::FormattingProperty::Bool(val))), Value::String(val) => Ok(FormattingProperty(lsp::FormattingProperty::String(val))), _ => bail!("expected a string, boolean or integer"), } } fn to_value(&self) -> Value { match self.0 { lsp::FormattingProperty::Bool(val) => Value::Bool(val), lsp::FormattingProperty::Number(val) => Value::Int(val as _), lsp::FormattingProperty::String(ref val) => Value::String(val.clone()), } } }