use super::StdioProvider;
use rootle_provider::{Capabilities, ErrorKind, ProviderError, ProviderResult};
use serde_json::{Value, json};
impl StdioProvider {
pub(super) fn handshake(&self) -> ProviderResult<Value> {
let mut params = json!({ "protocol": 1 });
if self.cache_bytes > 0 {
params["cache_bytes"] = json!(self.cache_bytes);
}
if let Some(dir) = &self.cache_dir {
params["cache_dir"] = json!(dir.to_string_lossy());
}
let reply = self.exchange("initialize", params, false)?;
let protocol = reply.get("protocol").and_then(Value::as_u64).unwrap_or(1);
let session = self.shared.routing.lock().session;
if protocol != 1 {
crate::trace::lifecycle("handshake", |fields| {
fields.insert("session".into(), serde_json::json!(session.value()));
fields.insert("protocol".into(), serde_json::json!(protocol));
fields.insert("outcome".into(), serde_json::json!("unsupported_protocol"));
});
return Err(ProviderError::new(
ErrorKind::Provider,
format!("unsupported provider protocol {protocol}"),
));
}
crate::trace::lifecycle("handshake", |fields| {
fields.insert("session".into(), serde_json::json!(session.value()));
fields.insert("protocol".into(), serde_json::json!(protocol));
fields.insert("outcome".into(), serde_json::json!("ok"));
});
Ok(reply)
}
pub(super) fn initialize_from(mut self, reply: Value) -> ProviderResult<Self> {
if let Some(name) = reply.get("name").and_then(Value::as_str) {
self.name = format!("stdio:{name}");
}
if let Some(icon) = reply.get("icon").and_then(Value::as_str) {
self.icon = Some(icon.to_string());
}
if let Some(caps) = reply.get("capabilities") {
self.capabilities = Capabilities {
orgs: caps.get("orgs").and_then(Value::as_bool).unwrap_or(true),
code_search: caps
.get("code_search")
.and_then(Value::as_bool)
.unwrap_or(true),
file_search: caps
.get("file_search")
.and_then(Value::as_bool)
.unwrap_or_else(|| {
caps.get("code_search")
.and_then(Value::as_bool)
.unwrap_or(true)
}),
refs: caps.get("refs").and_then(Value::as_bool).unwrap_or(false),
log: caps.get("log").and_then(Value::as_bool).unwrap_or(false),
blame: caps.get("blame").and_then(Value::as_bool).unwrap_or(false),
commit: caps.get("commit").and_then(Value::as_bool).unwrap_or(false),
};
}
if let Some(bytes) = reply.pointer("/cache/bytes").and_then(Value::as_u64) {
*self.cache_used.lock() = Some(bytes);
}
Ok(self)
}
}