@@ -1,11 +1,11 @@
1use crate::{
1use crate::{
2 transport::{Payload, Transport},
2 transport::{Payload, Transport},
3− Error, Notification,
3+ Call, Error,
6type Result<T> = core::result::Result<T, Error>;
6type Result<T> = core::result::Result<T, Error>;
8−use helix_core::{State, Transaction};
8+use helix_core::{ChangeSet, Transaction};
9use helix_view::Document;
9use helix_view::Document;
11// use std::collections::HashMap;
11// use std::collections::HashMap;
@@ -27,7 +27,7 @@ pub struct Client {
27 stderr: BufReader<ChildStderr>,
27 stderr: BufReader<ChildStderr>,
29 outgoing: Sender<Payload>,
29 outgoing: Sender<Payload>,
30− pub incoming: Receiver<Notification>,
30+ pub incoming: Receiver<Call>,
32 pub request_counter: u64,
32 pub request_counter: u64,
@@ -87,6 +87,7 @@ impl Client {
87 Ok(params)
87 Ok(params)
90+ /// Execute a RPC request on the language server.
90 pub async fn request<R: lsp::request::Request>(
91 pub async fn request<R: lsp::request::Request>(
91 &mut self,
92 &mut self,
92 params: R::Params,
93 params: R::Params,
@@ -126,6 +127,7 @@ impl Client {
126 Ok(response)
127 Ok(response)
130+ /// Send a RPC notification to the language server.
129 pub async fn notify<R: lsp::notification::Notification>(
131 pub async fn notify<R: lsp::notification::Notification>(
130 &mut self,
132 &mut self,
131 params: R::Params,
133 params: R::Params,
@@ -149,6 +151,35 @@ impl Client {
154+ /// Reply to a language server RPC call.
158+ result: core::result::Result<Value, jsonrpc::Error>,
160+ use jsonrpc::{Failure, Output, Success, Version};
162+ let output = match result {
163+ Ok(result) => Output::Success(Success {
164+ jsonrpc: Some(Version::V2),
168+ Err(error) => Output::Failure(Failure {
169+ jsonrpc: Some(Version::V2),
176+ .send(Payload::Response(output))
178+ .map_err(|e| Error::Other(e.into()))?;
152 // -------------------------------------------------------------------------------------------
183 // -------------------------------------------------------------------------------------------
153 // General messages
184 // General messages
154 // -------------------------------------------------------------------------------------------
185 // -------------------------------------------------------------------------------------------
@@ -163,7 +194,9 @@ impl Client {
163 // root_uri: Some(lsp_types::Url::parse("file://localhost/")?),
194 // root_uri: Some(lsp_types::Url::parse("file://localhost/")?),
164 root_uri: None, // set to project root in the future
195 root_uri: None, // set to project root in the future
165 initialization_options: None,
196 initialization_options: None,
166− capabilities: lsp::ClientCapabilities::default(),
197+ capabilities: lsp::ClientCapabilities {
198+ ..Default::default()
167 trace: None,
200 trace: None,
168 workspace_folders: None,
201 workspace_folders: None,
169 client_info: None,
202 client_info: None,
@@ -203,23 +236,107 @@ impl Client {
239+ fn to_changes(changeset: &ChangeSet) -> Vec<lsp::TextDocumentContentChangeEvent> {
240+ let mut iter = changeset.changes().iter().peekable();
241+ let mut old_pos = 0;
243+ let mut changes = Vec::new();
245+ use crate::util::pos_to_lsp_pos;
246+ use helix_core::Operation::*;
249+ let rope = helix_core::Rope::from("");
250+ let old_text = rope.slice(..);
252+ while let Some(change) = iter.next() {
253+ let len = match change {
254+ Delete(i) | Retain(i) => *i,
257+ let old_end = old_pos + len;
262+ let start = pos_to_lsp_pos(&old_text, old_pos);
263+ let end = pos_to_lsp_pos(&old_text, old_end);
265+ // a subsequent ins means a replace, consume it
266+ if let Some(Insert(s)) = iter.peek() {
270+ changes.push(lsp::TextDocumentContentChangeEvent {
271+ range: Some(lsp::Range::new(start, end)),
277+ changes.push(lsp::TextDocumentContentChangeEvent {
278+ range: Some(lsp::Range::new(start, end)),
279+ text: "".to_string(),
285+ let start = pos_to_lsp_pos(&old_text, old_pos);
288+ changes.push(lsp::TextDocumentContentChangeEvent {
289+ range: Some(lsp::Range::new(start, start)),
206 // TODO: trigger any time history.commit_revision happens
301 // TODO: trigger any time history.commit_revision happens
207 pub async fn text_document_did_change(
302 pub async fn text_document_did_change(
208 &mut self,
303 &mut self,
209 doc: &Document,
304 doc: &Document,
210 transaction: &Transaction,
305 transaction: &Transaction,
211 ) -> Result<()> {
306 ) -> Result<()> {
307+ // figure out what kind of sync the server supports
309+ let capabilities = self.capabilities.as_ref().unwrap(); // TODO: needs post init
311+ let sync_capabilities = match capabilities.text_document_sync {
312+ Some(lsp::TextDocumentSyncCapability::Kind(kind)) => kind,
313+ Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
317+ // None | SyncOptions { changes: None }
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?
330+ lsp::TextDocumentSyncKind::Incremental => Self::to_changes(transaction.changes()),
331+ lsp::TextDocumentSyncKind::None => return Ok(()),
212 self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
334 self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
213 text_document: lsp::VersionedTextDocumentIdentifier::new(
335 text_document: lsp::VersionedTextDocumentIdentifier::new(
214 lsp::Url::from_file_path(doc.path().unwrap()).unwrap(),
336 lsp::Url::from_file_path(doc.path().unwrap()).unwrap(),
215 doc.version,
337 doc.version,
217− content_changes: vec![lsp::TextDocumentContentChangeEvent {
339+ content_changes: changes,
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?