lsp_bin/
client.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::{collections::HashMap, fmt::Display, pin::Pin};

use bevy_ecs::system::Resource;
use futures::FutureExt;
use lsp_core::client::{Client, ClientSync, Resp};
use lsp_types::{Diagnostic, MessageType, Url};
use tracing::info;

pub mod reqwest {
    pub use reqwest::{
        header::{HeaderMap, HeaderName, HeaderValue},
        Error, StatusCode, Url,
    };
}

#[derive(Resource, Clone)]
pub struct TowerClient {
    client: tower_lsp::Client,
    handle: tokio::runtime::Handle,
}
impl TowerClient {
    pub fn new(client: tower_lsp::Client) -> Self {
        Self {
            client,
            handle: tokio::runtime::Handle::current(),
        }
    }
}

impl ClientSync for TowerClient {
    fn spawn<F: std::future::Future<Output = ()> + Send + 'static>(&self, fut: F) {
        let handle = std::thread::current();
        info!("Spawn threaad name {:?}", handle.id());
        self.handle.spawn(fut);
        // info!("Should spawn but won't!");
    }

    fn fetch(
        &self,
        url: &str,
        headers: &HashMap<String, String>,
    ) -> Pin<Box<dyn Send + std::future::Future<Output = Result<Resp, String>>>> {
        use tokio::{fs::File, io::AsyncReadExt};
        use tracing::{debug, error, info};
        info!("Should fetch, fetching!");

        let m_url = reqwest::Url::parse(url);

        let client = ::reqwest::Client::new();
        let builder = client.get(url);
        let builder = headers
            .into_iter()
            .fold(builder, |builder, (k, v)| builder.header(k, v));

        return async {
            let url = m_url.map_err(|_| String::from("invalid url!"))?;
            info!("Found url {} {}", url.scheme(), url);
            if url.scheme() == "file" {
                let mut file = File::open(url.path())
                    .await
                    .map_err(|_| format!("File not found {}", url.path()))?;
                let mut body = String::new();
                file.read_to_string(&mut body)
                    .await
                    .map_err(|_| format!("Failed to read file"))?;
                let status = 200;
                let headers = Vec::new();
                return Ok(Resp {
                    headers,
                    body,
                    status,
                });
            }

            debug!("sending blocking");
            let resp = match builder.send().await {
                Ok(x) => x,
                Err(e) => {
                    error!(error = ?e);
                    return Err(e.to_string());
                }
            };

            let status = resp.status().as_u16();
            let headers: Vec<_> = resp
                .headers()
                .iter()
                .flat_map(|(h, v)| {
                    if let Ok(value) = v.to_str() {
                        Some((h.to_string(), value.to_string()))
                    } else {
                        None
                    }
                })
                .collect();
            debug!("got resp");
            let body = resp.text().await.unwrap();

            Ok(Resp {
                headers,
                body,
                status,
            })
        }
        .boxed();
    }
}

#[tower_lsp::async_trait]
impl Client for TowerClient {
    async fn log_message<M: Display + Sync + Send + 'static>(&self, ty: MessageType, msg: M) -> () {
        self.client.log_message(ty, msg).await;
    }

    async fn publish_diagnostics(
        &self,
        uri: Url,
        diags: Vec<Diagnostic>,
        version: Option<i32>,
    ) -> () {
        self.client.publish_diagnostics(uri, diags, version).await;
    }
}