Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-lsp/src/config.rs')
-rw-r--r--helix-lsp/src/config.rs67
1 files changed, 67 insertions, 0 deletions
diff --git a/helix-lsp/src/config.rs b/helix-lsp/src/config.rs
new file mode 100644
index 00000000..6d9f8008
--- /dev/null
+++ b/helix-lsp/src/config.rs
@@ -0,0 +1,67 @@
+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<String> = None,
+ /// A list of arguments to pass to the language server binary
+ #[read = deref]
+ args: List<String> = List::default(),
+ /// Any environment variables that will be used when starting the language server
+ enviorment: Map<String> = Map::default(),
+ /// LSP initialization options
+ #[name = "config"]
+ server_config: Option<Box<serde_json::Value>> = 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<FormattingProperty> = Map::default()
+ }
+}
+
+type FormatConfig = HashMap<std::string::String, lsp::FormattingProperty>;
+
+fn fold_format_config(config: &Map<FormattingProperty>, 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<Self> {
+ 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()),
+ }
+ }
+}