@@ -1,27 +1,26 @@
1mod transport;
2mod transport;
3−use transport::{Payload, Transport};
5−use helix_core::{State, Transaction};
7−// use std::collections::HashMap;
9use jsonrpc_core as jsonrpc;
4use jsonrpc_core as jsonrpc;
10use lsp_types as lsp;
5use lsp_types as lsp;
11−use serde_json::Value;
13−use serde::{Deserialize, Serialize};
7+pub use client::Client;
15−pub use lsp::Position;
8+pub use lsp::{Position, Url};
18−use smol::{
10+use serde::{Deserialize, Serialize};
19− channel::{Receiver, Sender},
11+use thiserror::Error;
20− io::{BufReader, BufWriter},
12+
21− // prelude::*,
13+#[derive(Error, Debug)]
22− process::{Child, ChildStderr, Command, Stdio},
14+pub enum Error {
23− Executor,
15+ #[error("protocol error: {0}")]
16+ Rpc(#[from] jsonrpc::Error),
17+ #[error("failed to parse: {0}")]
18+ Parse(#[from] serde_json::Error),
19+ #[error("request timed out")]
21+ #[error(transparent)]
22+ Other(#[from] anyhow::Error),
26pub mod util {
25pub mod util {
27 use super::*;
26 use super::*;
@@ -68,209 +67,3 @@ impl Notification {
74− stderr: BufReader<ChildStderr>,
76− outgoing: Sender<Payload>,
77− pub incoming: Receiver<Notification>,
79− pub request_counter: u64,
81− capabilities: Option<lsp::ServerCapabilities>,
82− // TODO: handle PublishDiagnostics Version
83− // diagnostics: HashMap<lsp::Url, Vec<lsp::Diagnostic>>,
87− pub fn start(ex: &Executor, cmd: &str, args: &[String]) -> Self {
88− let mut process = Command::new(cmd)
90− .stdin(Stdio::piped())
91− .stdout(Stdio::piped())
92− .stderr(Stdio::piped())
94− .expect("Failed to start language server");
95− // smol makes sure the process is reaped on drop, but using kill_on_drop(true) maybe?
97− // TODO: do we need bufreader/writer here? or do we use async wrappers on unblock?
98− let writer = BufWriter::new(process.stdin.take().expect("Failed to open stdin"));
99− let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout"));
100− let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr"));
102− let (incoming, outgoing) = Transport::start(ex, reader, writer);
114− // diagnostics: HashMap::new(),
118− fn next_request_id(&mut self) -> jsonrpc::Id {
119− let id = jsonrpc::Id::Num(self.request_counter);
120− self.request_counter += 1;
124− fn to_params(value: Value) -> anyhow::Result<jsonrpc::Params> {
125− use jsonrpc::Params;
127− let params = match value {
128− Value::Null => Params::None,
129− Value::Bool(_) | Value::Number(_) | Value::String(_) => Params::Array(vec![value]),
130− Value::Array(vec) => Params::Array(vec),
131− Value::Object(map) => Params::Map(map),
137− pub async fn request<R: lsp::request::Request>(
140− ) -> anyhow::Result<R::Result>
142− R::Params: serde::Serialize,
143− R::Result: core::fmt::Debug, // TODO: temporary
145− let params = serde_json::to_value(params)?;
147− let request = jsonrpc::MethodCall {
148− jsonrpc: Some(jsonrpc::Version::V2),
149− id: self.next_request_id(),
150− method: R::METHOD.to_string(),
151− params: Self::to_params(params)?,
154− let (tx, rx) = smol::channel::bounded::<anyhow::Result<Value>>(1);
157− .send(Payload::Request {
163− let response = rx.recv().await??;
165− let response = serde_json::from_value(response)?;
167− // TODO: we should pass request to a sender thread via a channel
168− // so it can't be interleaved
170− // TODO: responses can be out of order, we need to register a single shot response channel
175− pub async fn notify<R: lsp::notification::Notification>(
178− ) -> anyhow::Result<()>
180− R::Params: serde::Serialize,
182− let params = serde_json::to_value(params)?;
184− let notification = jsonrpc::Notification {
185− jsonrpc: Some(jsonrpc::Version::V2),
186− method: R::METHOD.to_string(),
187− params: Self::to_params(params)?,
191− .send(Payload::Notification(notification))
197− // -------------------------------------------------------------------------------------------
199− // -------------------------------------------------------------------------------------------
201− pub async fn initialize(&mut self) -> anyhow::Result<()> {
202− // TODO: delay any requests that are triggered prior to initialize
204− #[allow(deprecated)]
205− let params = lsp::InitializeParams {
206− process_id: Some(u64::from(std::process::id())),
208− // root_uri: Some(lsp_types::Url::parse("file://localhost/")?),
209− root_uri: None, // set to project root in the future
210− initialization_options: None,
211− capabilities: lsp::ClientCapabilities::default(),
213− workspace_folders: None,
217− let response = self.request::<lsp::request::Initialize>(params).await?;
218− self.capabilities = Some(response.capabilities);
220− // next up, notify<initialized>
221− self.notify::<lsp::notification::Initialized>(lsp::InitializedParams {})
227− pub async fn shutdown(&mut self) -> anyhow::Result<()> {
228− self.request::<lsp::request::Shutdown>(()).await
231− pub async fn exit(&mut self) -> anyhow::Result<()> {
232− self.notify::<lsp::notification::Exit>(()).await
235− // -------------------------------------------------------------------------------------------
237− // -------------------------------------------------------------------------------------------
239− pub async fn text_document_did_open(&mut self, state: &State) -> anyhow::Result<()> {
240− self.notify::<lsp::notification::DidOpenTextDocument>(lsp::DidOpenTextDocumentParams {
241− text_document: lsp::TextDocumentItem {
242− uri: lsp::Url::from_file_path(state.path().unwrap()).unwrap(),
243− language_id: "rust".to_string(), // TODO: hardcoded for now
244− version: state.version,
245− text: String::from(&state.doc),
251− // TODO: trigger any time history.commit_revision happens
252− pub async fn text_document_did_change(
255− transaction: &Transaction,
256− ) -> anyhow::Result<()> {
257− self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
258− text_document: lsp::VersionedTextDocumentIdentifier::new(
259− lsp::Url::from_file_path(state.path().unwrap()).unwrap(),
262− content_changes: vec![], // TODO: probably need old_state here too?
267− pub async fn text_document_did_close(&mut self) -> anyhow::Result<()> {
271− // will_save / will_save_wait_until
273− pub async fn text_document_did_save(&mut self) -> anyhow::Result<()> {