ra_multiplex/
ext.rs

1use std::env;
2
3use anyhow::{bail, Context, Result};
4use serde::de::{DeserializeOwned, IgnoredAny};
5use tokio::io::BufReader;
6
7use crate::config::Config;
8use crate::lsp::ext::{self, LspMuxOptions, StatusResponse};
9use crate::lsp::jsonrpc::{Message, Request, RequestId, Version};
10use crate::lsp::transport::{LspReader, LspWriter};
11use crate::lsp::{InitializationOptions, InitializeParams};
12use crate::socketwrapper::Stream;
13
14pub async fn ext_request<T>(config: &Config, method: ext::Request) -> Result<T>
15where
16    T: DeserializeOwned,
17{
18    let (reader, writer) = Stream::connect(&config.connect)
19        .await
20        .context("connect")?
21        .into_split();
22    let mut writer = LspWriter::new(writer, "lspmux");
23    let mut reader = LspReader::new(BufReader::new(reader), "lspmux");
24
25    writer
26        .write_message(
27            &Request {
28                jsonrpc: Version,
29                method: "initialize".into(),
30                params: serde_json::to_value(InitializeParams {
31                    initialization_options: Some(InitializationOptions {
32                        lsp_mux: Some(LspMuxOptions {
33                            version: LspMuxOptions::PROTOCOL_VERSION.into(),
34                            method,
35                        }),
36                        other_options: serde_json::Map::default(),
37                    }),
38                    process_id: None,
39                    client_info: None,
40                    locale: None,
41                    root_path: None,
42                    root_uri: None,
43                    capabilities: None,
44                    trace: None,
45                    workspace_folders: Vec::new(),
46                })
47                .unwrap(),
48                id: RequestId::Number(0),
49            }
50            .into(),
51        )
52        .await
53        .context("send lspmux request")?;
54
55    match reader
56        .read_message()
57        .await
58        .context("read lspmux response")?
59        .context("stream ended")?
60        .into_response()
61        .context("received message was not a response")?
62    {
63        Ok(success) => serde_json::from_value(success.result).context("parse response result"),
64        Err(error) => bail!(
65            "received error response: {msg:?}",
66            msg = Message::ResponseError(error),
67        ),
68    }
69}
70
71pub fn config(config: &Config) -> Result<()> {
72    println!("{config:#?}");
73    Ok(())
74}
75
76pub async fn status(config: &Config, json: bool) -> Result<()> {
77    let res = ext_request::<StatusResponse>(config, ext::Request::Status {}).await?;
78
79    if json {
80        let json = serde_json::to_string(&res).unwrap();
81        println!("{json}");
82        return Ok(());
83    }
84
85    for instance in res.instances {
86        println!("- Instance");
87        println!("  pid: {}", instance.pid);
88        println!("  server: {:?} {:?}", instance.server, instance.args);
89        if !instance.env.is_empty() {
90            println!("  server env:");
91            for (key, val) in instance.env {
92                println!("    {key} = {val}");
93            }
94        }
95        println!("  path: {:?}", instance.workspace_root);
96        let now = time::OffsetDateTime::now_utc().unix_timestamp();
97        println!("  last used: {}s ago", now - instance.last_used);
98        println!("  registered dynamic capabilities:");
99        for cap in instance.registered_dyn_capabilities {
100            println!("    - {}", cap);
101        }
102        println!("  clients:");
103        for client in instance.clients {
104            println!("    - Client");
105            println!("      id: {}", client.id);
106            println!("      files:");
107            for file in client.files {
108                println!("        - {}", file);
109            }
110        }
111    }
112    Ok(())
113}
114
115pub async fn reload(config: &Config) -> Result<()> {
116    let cwd = env::current_dir()
117        .context("unable to get current_dir")?
118        .to_str()
119        .context("current_dir is not valid utf-8")?
120        .to_owned();
121    ext_request::<IgnoredAny>(config, ext::Request::Reload { cwd }).await?;
122    Ok(())
123}