on master help sign in
Text change generation, RPC call handling.
commitcc6bdf8f66889087223d9a8491479ceecc09a663 authorBlaž Hrastnik <blaz@mxxn.io> dateFri 23 Oct 2020, 18:48 (6 years ago) parentaf19244
7 files changed+225−77
helix-core/src/lib.rs+1−1 helix-core/src/transaction.rs+8−1 helix-lsp/src/client.rs+127−10 helix-lsp/src/lib.rs+10−15 helix-lsp/src/transport.rs+26−13 helix-term/src/application.rs+50−37 helix-view/src/keymap.rs+3
helix-core/src/lib.rs+1−1
@@ -27,4 +27,4 @@ pub use diagnostic::Diagnostic;
2727pub use history::History;
2828pub use state::State;
2929
30−pub use transaction::{Assoc, Change, ChangeSet, Transaction};
30+pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
helix-core/src/transaction.rs+8−1
@@ -5,8 +5,9 @@ use std::convert::TryFrom;
55/// (from, to, replacement)
66pub type Change = (usize, usize, Option<Tendril>);
77
8+// TODO: pub(crate)
89#[derive(Debug, Clone, PartialEq, Eq)]
9−pub(crate) enum Operation {
10+pub enum Operation {
1011 /// Move cursor by n characters.
1112 Retain(usize),
1213 /// Delete n characters.
@@ -40,6 +41,12 @@ impl ChangeSet {
4041 }
4142
4243 // TODO: from iter
44+ //
45+
46+ #[doc(hidden)] // used by lsp to convert to LSP changes
47+ pub fn changes(&self) -> &[Operation] {
48+ &self.changes
49+ }
4350
4451 #[must_use]
4552 fn len_after(&self) -> usize {
helix-lsp/src/client.rs+127−10
@@ -1,11 +1,11 @@
11use crate::{
22 transport::{Payload, Transport},
3− Error, Notification,
3+ Call, Error,
44};
55
66type Result<T> = core::result::Result<T, Error>;
77
8−use helix_core::{State, Transaction};
8+use helix_core::{ChangeSet, Transaction};
99use helix_view::Document;
1010
1111// use std::collections::HashMap;
@@ -27,7 +27,7 @@ pub struct Client {
2727 stderr: BufReader<ChildStderr>,
2828
2929 outgoing: Sender<Payload>,
30− pub incoming: Receiver<Notification>,
30+ pub incoming: Receiver<Call>,
3131
3232 pub request_counter: u64,
3333
@@ -87,6 +87,7 @@ impl Client {
8787 Ok(params)
8888 }
8989
90+ /// Execute a RPC request on the language server.
9091 pub async fn request<R: lsp::request::Request>(
9192 &mut self,
9293 params: R::Params,
@@ -126,6 +127,7 @@ impl Client {
126127 Ok(response)
127128 }
128129
130+ /// Send a RPC notification to the language server.
129131 pub async fn notify<R: lsp::notification::Notification>(
130132 &mut self,
131133 params: R::Params,
@@ -149,6 +151,35 @@ impl Client {
149151 Ok(())
150152 }
151153
154+ /// Reply to a language server RPC call.
155+ pub async fn reply(
156+ &mut self,
157+ id: jsonrpc::Id,
158+ result: core::result::Result<Value, jsonrpc::Error>,
159+ ) -> Result<()> {
160+ use jsonrpc::{Failure, Output, Success, Version};
161+
162+ let output = match result {
163+ Ok(result) => Output::Success(Success {
164+ jsonrpc: Some(Version::V2),
165+ id,
166+ result,
167+ }),
168+ Err(error) => Output::Failure(Failure {
169+ jsonrpc: Some(Version::V2),
170+ id,
171+ error,
172+ }),
173+ };
174+
175+ self.outgoing
176+ .send(Payload::Response(output))
177+ .await
178+ .map_err(|e| Error::Other(e.into()))?;
179+
180+ Ok(())
181+ }
182+
152183 // -------------------------------------------------------------------------------------------
153184 // General messages
154185 // -------------------------------------------------------------------------------------------
@@ -163,7 +194,9 @@ impl Client {
163194 // root_uri: Some(lsp_types::Url::parse("file://localhost/")?),
164195 root_uri: None, // set to project root in the future
165196 initialization_options: None,
166− capabilities: lsp::ClientCapabilities::default(),
197+ capabilities: lsp::ClientCapabilities {
198+ ..Default::default()
199+ },
167200 trace: None,
168201 workspace_folders: None,
169202 client_info: None,
@@ -203,23 +236,107 @@ impl Client {
203236 .await
204237 }
205238
239+ fn to_changes(changeset: &ChangeSet) -> Vec<lsp::TextDocumentContentChangeEvent> {
240+ let mut iter = changeset.changes().iter().peekable();
241+ let mut old_pos = 0;
242+
243+ let mut changes = Vec::new();
244+
245+ use crate::util::pos_to_lsp_pos;
246+ use helix_core::Operation::*;
247+
248+ // TEMP
249+ let rope = helix_core::Rope::from("");
250+ let old_text = rope.slice(..);
251+
252+ while let Some(change) = iter.next() {
253+ let len = match change {
254+ Delete(i) | Retain(i) => *i,
255+ Insert(_) => 0,
256+ };
257+ let old_end = old_pos + len;
258+
259+ match change {
260+ Retain(_) => {}
261+ Delete(_) => {
262+ let start = pos_to_lsp_pos(&old_text, old_pos);
263+ let end = pos_to_lsp_pos(&old_text, old_end);
264+
265+ // a subsequent ins means a replace, consume it
266+ if let Some(Insert(s)) = iter.peek() {
267+ iter.next();
268+
269+ // replacement
270+ changes.push(lsp::TextDocumentContentChangeEvent {
271+ range: Some(lsp::Range::new(start, end)),
272+ text: s.into(),
273+ range_length: None,
274+ });
275+ } else {
276+ // deletion
277+ changes.push(lsp::TextDocumentContentChangeEvent {
278+ range: Some(lsp::Range::new(start, end)),
279+ text: "".to_string(),
280+ range_length: None,
281+ });
282+ };
283+ }
284+ Insert(s) => {
285+ let start = pos_to_lsp_pos(&old_text, old_pos);
286+
287+ // insert
288+ changes.push(lsp::TextDocumentContentChangeEvent {
289+ range: Some(lsp::Range::new(start, start)),
290+ text: s.into(),
291+ range_length: None,
292+ });
293+ }
294+ }
295+ old_pos = old_end;
296+ }
297+
298+ changes
299+ }
300+
206301 // TODO: trigger any time history.commit_revision happens
207302 pub async fn text_document_did_change(
208303 &mut self,
209304 doc: &Document,
210305 transaction: &Transaction,
211306 ) -> Result<()> {
307+ // figure out what kind of sync the server supports
308+
309+ let capabilities = self.capabilities.as_ref().unwrap(); // TODO: needs post init
310+
311+ let sync_capabilities = match capabilities.text_document_sync {
312+ Some(lsp::TextDocumentSyncCapability::Kind(kind)) => kind,
313+ Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
314+ change: Some(kind),
315+ ..
316+ })) => kind,
317+ // None | SyncOptions { changes: None }
318+ _ => return Ok(()),
319+ };
320+
321+ let changes = match sync_capabilities {
322+ lsp::TextDocumentSyncKind::Full => {
323+ vec![lsp::TextDocumentContentChangeEvent {
324+ // range = None -> whole document
325+ range: None, //Some(Range)
326+ range_length: None, // u64 apparently deprecated
327+ text: "".to_string(),
328+ }] // TODO: probably need old_state here too?
329+ }
330+ lsp::TextDocumentSyncKind::Incremental => Self::to_changes(transaction.changes()),
331+ lsp::TextDocumentSyncKind::None => return Ok(()),
332+ };
333+
212334 self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
213335 text_document: lsp::VersionedTextDocumentIdentifier::new(
214336 lsp::Url::from_file_path(doc.path().unwrap()).unwrap(),
215337 doc.version,
216338 ),
217− content_changes: vec![lsp::TextDocumentContentChangeEvent {
218− // range = None -> whole document
219− range: None, //Some(Range)
220− range_length: None, // u64 apparently deprecated
221− text: "".to_string(),
222− }], // TODO: probably need old_state here too?
339+ content_changes: changes,
223340 })
224341 .await
225342 }
helix-lsp/src/lib.rs+10−15
@@ -1,13 +1,12 @@
11mod client;
22mod transport;
33
4−use jsonrpc_core as jsonrpc;
5−use lsp_types as lsp;
4+pub use jsonrpc_core as jsonrpc;
5+pub use lsp_types as lsp;
66
77pub use client::Client;
88pub use lsp::{Position, Url};
99
10−use serde::{Deserialize, Serialize};
1110use thiserror::Error;
1211
1312#[derive(Error, Debug)]
@@ -30,19 +29,13 @@ pub mod util {
3029 let line_start = doc.char_to_utf16_cu(line);
3130 doc.utf16_cu_to_char(pos.character as usize + line_start)
3231 }
33−}
32+ pub fn pos_to_lsp_pos(doc: &helix_core::RopeSlice, pos: usize) -> lsp::Position {
33+ let line = doc.char_to_line(pos);
34+ let line_start = doc.char_to_utf16_cu(line);
35+ let col = doc.char_to_utf16_cu(pos) - line_start;
3436
35−/// A type representing all possible values sent from the server to the client.
36−#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
37−#[serde(deny_unknown_fields)]
38−#[serde(untagged)]
39−enum Message {
40− /// A regular JSON-RPC request output (single response).
41− Output(jsonrpc::Output),
42− /// A notification.
43− Notification(jsonrpc::Notification),
44− /// A JSON-RPC request
45− Call(jsonrpc::Call),
37+ lsp::Position::new(line as u64, col as u64)
38+ }
4639}
4740
4841#[derive(Debug, PartialEq, Clone)]
@@ -67,3 +60,5 @@ impl Notification {
6760 }
6861 }
6962}
63+
64+pub use jsonrpc::Call;
helix-lsp/src/transport.rs+26−13
@@ -2,7 +2,7 @@ use std::collections::HashMap;
22
33use log::debug;
44
5−use crate::{Error, Message, Notification};
5+use crate::{Error, Notification};
66
77type Result<T> = core::result::Result<T, Error>;
88
@@ -24,10 +24,23 @@ pub(crate) enum Payload {
2424 value: jsonrpc::MethodCall,
2525 },
2626 Notification(jsonrpc::Notification),
27+ Response(jsonrpc::Output),
28+}
29+
30+use serde::{Deserialize, Serialize};
31+/// A type representing all possible values sent from the server to the client.
32+#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
33+#[serde(deny_unknown_fields)]
34+#[serde(untagged)]
35+enum Message {
36+ /// A regular JSON-RPC request output (single response).
37+ Output(jsonrpc::Output),
38+ /// A JSON-RPC request or notification.
39+ Call(jsonrpc::Call),
2740}
2841
2942pub(crate) struct Transport {
30− incoming: Sender<Notification>, // TODO Notification | Call
43+ incoming: Sender<jsonrpc::Call>,
3144 outgoing: Receiver<Payload>,
3245
3346 pending_requests: HashMap<jsonrpc::Id, Sender<Result<Value>>>,
@@ -42,7 +55,7 @@ impl Transport {
4255 ex: &Executor,
4356 reader: BufReader<ChildStdout>,
4457 writer: BufWriter<ChildStdin>,
45− ) -> (Receiver<Notification>, Sender<Payload>) {
58+ ) -> (Receiver<jsonrpc::Call>, Sender<Payload>) {
4659 let (incoming, rx) = smol::channel::unbounded();
4760 let (tx, outgoing) = smol::channel::unbounded();
4861
@@ -112,6 +125,10 @@ impl Transport {
112125 let json = serde_json::to_string(&value)?;
113126 self.send(json).await
114127 }
128+ Payload::Response(error) => {
129+ let json = serde_json::to_string(&error)?;
130+ self.send(json).await
131+ }
115132 }
116133 }
117134
@@ -131,24 +148,18 @@ impl Transport {
131148 Ok(())
132149 }
133150
134− pub async fn recv_msg(&mut self, msg: Message) -> anyhow::Result<()> {
151+ async fn recv_msg(&mut self, msg: Message) -> anyhow::Result<()> {
135152 match msg {
136153 Message::Output(output) => self.recv_response(output).await?,
137− Message::Notification(jsonrpc::Notification { method, params, .. }) => {
138− let notification = Notification::parse(&method, params);
139−
140− debug!("<- {} {:?}", method, notification);
141− self.incoming.send(notification).await?;
142− }
143154 Message::Call(call) => {
144− debug!("<- {:?}", call);
145− // dispatch
155+ self.incoming.send(call).await?;
156+ // let notification = Notification::parse(&method, params);
146157 }
147158 };
148159 Ok(())
149160 }
150161
151− pub async fn recv_response(&mut self, output: jsonrpc::Output) -> anyhow::Result<()> {
162+ async fn recv_response(&mut self, output: jsonrpc::Output) -> anyhow::Result<()> {
152163 match output {
153164 jsonrpc::Output::Success(jsonrpc::Success { id, result, .. }) => {
154165 debug!("<- {}", result);
@@ -191,6 +202,8 @@ impl Transport {
191202 }
192203 let msg = msg.unwrap();
193204
205+ debug!("<- {:?}", msg);
206+
194207 self.recv_msg(msg).await.unwrap();
195208 }
196209 }
helix-term/src/application.rs+50−37
@@ -433,8 +433,8 @@ impl<'a> Application<'a> {
433433 event = reader.next().fuse() => {
434434 self.handle_terminal_events(event).await
435435 }
436− notification = self.lsp.incoming.next().fuse() => {
437− self.handle_lsp_notification(notification).await
436+ call = self.lsp.incoming.next().fuse() => {
437+ self.handle_lsp_message(call).await
438438 }
439439 }
440440 }
@@ -566,43 +566,56 @@ impl<'a> Application<'a> {
566566 };
567567 }
568568
569− pub async fn handle_lsp_notification(&mut self, notification: Option<helix_lsp::Notification>) {
570− use helix_lsp::Notification;
571− match notification {
572− Some(Notification::PublishDiagnostics(params)) => {
573− let path = Some(params.uri.to_file_path().unwrap());
574− let view = self
575− .editor
576− .views
577− .iter_mut()
578− .find(|view| view.doc.path == path);
579−
580− if let Some(view) = view {
581− let doc = view.doc.text().slice(..);
582− let diagnostics = params
583− .diagnostics
584− .into_iter()
585− .map(|diagnostic| {
586− use helix_lsp::util::lsp_pos_to_pos;
587− let start = lsp_pos_to_pos(&doc, diagnostic.range.start);
588− let end = lsp_pos_to_pos(&doc, diagnostic.range.end);
589−
590− helix_core::Diagnostic {
591− range: (start, end),
592− line: diagnostic.range.start.line as usize,
593− message: diagnostic.message,
594− // severity
595− // code
596− // source
597− }
598− })
599− .collect();
600−
601− view.doc.diagnostics = diagnostics;
602−
603− self.render();
569+ pub async fn handle_lsp_message(&mut self, call: Option<helix_lsp::Call>) {
570+ use helix_lsp::{Call, Notification};
571+ match call {
572+ Some(Call::Notification(helix_lsp::jsonrpc::Notification {
573+ method, params, ..
574+ })) => {
575+ let notification = Notification::parse(&method, params);
576+ match notification {
577+ Notification::PublishDiagnostics(params) => {
578+ let path = Some(params.uri.to_file_path().unwrap());
579+ let view = self
580+ .editor
581+ .views
582+ .iter_mut()
583+ .find(|view| view.doc.path == path);
584+
585+ if let Some(view) = view {
586+ let doc = view.doc.text().slice(..);
587+ let diagnostics = params
588+ .diagnostics
589+ .into_iter()
590+ .map(|diagnostic| {
591+ use helix_lsp::util::lsp_pos_to_pos;
592+ let start = lsp_pos_to_pos(&doc, diagnostic.range.start);
593+ let end = lsp_pos_to_pos(&doc, diagnostic.range.end);
594+
595+ helix_core::Diagnostic {
596+ range: (start, end),
597+ line: diagnostic.range.start.line as usize,
598+ message: diagnostic.message,
599+ // severity
600+ // code
601+ // source
602+ }
603+ })
604+ .collect();
605+
606+ view.doc.diagnostics = diagnostics;
607+
608+ self.render();
609+ }
610+ }
611+ _ => unreachable!(),
604612 }
605613 }
614+ Some(Call::MethodCall(call)) => {
615+ // TODO: need to make Result<Value, Error>
616+
617+ unimplemented!("{:?}", call)
618+ }
606619 _ => unreachable!(),
607620 }
608621 }
helix-view/src/keymap.rs+3
@@ -82,6 +82,9 @@ use std::collections::HashMap;
8282// = = align?
8383// + =
8484// }
85+//
86+// gd = goto definition
87+// gr = goto reference
8588// }
8689
8790#[cfg(feature = "term")]