use std::collections::VecDeque;
use std::path::PathBuf;
use anyhow::Context;
use lsp_server::ErrorCode;
use lsp_types::request::WorkspaceConfiguration;
use lsp_types::{ClientCapabilities, ConfigurationItem, ConfigurationParams};
use serde_json::Value;
use tracing::{debug, error, warn};
use crate::lsp::capabilities::client::ClientCapabilitiesExt;
use crate::lsp::result::{LSPResult, LSPResultEx};
use crate::server::client::Requester;
use crate::server::schedule::Task;
#[derive(Debug, Default, Clone)]
pub struct Config {
pub unmanaged_core_path: Option<PathBuf>,
pub trace_macro_diagnostics: bool,
pub enable_proc_macros: bool,
}
impl Config {
pub fn reload(
&mut self,
requester: &mut Requester<'_>,
client_capabilities: &ClientCapabilities,
) -> LSPResult<()> {
if !client_capabilities.workspace_configuration_support() {
warn!(
"client does not support `workspace/configuration` requests, config will not be \
reloaded"
);
return Ok(());
}
let items = vec![
ConfigurationItem { scope_uri: None, section: Some("cairo1.corelibPath".to_owned()) },
ConfigurationItem {
scope_uri: None,
section: Some("cairo1.traceMacroDiagnostics".to_owned()),
},
ConfigurationItem {
scope_uri: None,
section: Some("cairo1.enableProcMacros".to_owned()),
},
];
let expected_len = items.len();
let handler = move |response: Vec<Value>| {
let response_len = response.len();
if response_len != expected_len {
error!(
"server returned unexpected number of configuration items, expected: \
{expected_len}, got: {response_len}"
);
return Task::nothing();
}
let mut response = VecDeque::from(response);
Task::local(move |state, _, _, _| {
state.config.unmanaged_core_path = response
.pop_front()
.as_ref()
.and_then(Value::as_str)
.filter(|s| !s.is_empty())
.map(Into::into);
state.config.trace_macro_diagnostics =
response.pop_front().as_ref().and_then(Value::as_bool).unwrap_or_default();
state.config.enable_proc_macros =
response.pop_front().as_ref().and_then(Value::as_bool).unwrap_or(false);
debug!("reloaded configuration: {:#?}", state.config);
state.proc_macro_controller.on_config_change(&mut state.db, &state.config);
})
};
requester
.request::<WorkspaceConfiguration>(ConfigurationParams { items }, handler)
.context("failed to query language client for configuration items")
.with_failure_code(ErrorCode::RequestFailed)
.inspect_err(|e| warn!("{e:?}"))
}
}