@@ -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 }