@@ -247,19 +247,47 @@ impl Client {
250+ // TODO: this is dumb. TextEdit describes changes to the initial doc (concurrent), but
251+ // TextDocumentContentChangeEvent describes a series of changes (sequential).
252+ // So S -> S1 -> S2, meaning positioning depends on the previous edits.
254+ // Calculation is therefore a bunch trickier.
250 pub fn changeset_to_changes(
255 pub fn changeset_to_changes(
251 old_text: &Rope,
256 old_text: &Rope,
252 changeset: &ChangeSet,
258 changeset: &ChangeSet,
253 ) -> Vec<lsp::TextDocumentContentChangeEvent> {
259 ) -> Vec<lsp::TextDocumentContentChangeEvent> {
254 let mut iter = changeset.changes().iter().peekable();
260 let mut iter = changeset.changes().iter().peekable();
255 let mut old_pos = 0;
261 let mut old_pos = 0;
262+ let mut new_pos = 0;
257 let mut changes = Vec::new();
264 let mut changes = Vec::new();
259 use crate::util::pos_to_lsp_pos;
266 use crate::util::pos_to_lsp_pos;
260 use helix_core::Operation::*;
267 use helix_core::Operation::*;
269+ // TODO: stolen from syntax.rs, share
270+ use helix_core::RopeSlice;
271+ fn traverse(pos: lsp::Position, text: RopeSlice) -> lsp::Position {
277+ // TODO: there should be a better way here
278+ for ch in text.chars() {
283+ character += ch.len_utf16() as u32;
286+ lsp::Position { line, character }
262 let old_text = old_text.slice(..);
289 let old_text = old_text.slice(..);
290+ let new_text = new_text.slice(..);
264 // TODO: verify this function, specifically line num counting
292 // TODO: verify this function, specifically line num counting
@@ -271,10 +299,12 @@ impl Client {
271 let mut old_end = old_pos + len;
299 let mut old_end = old_pos + len;
273 match change {
301 match change {
274− Retain(_) => {}
302+ Retain(i) => {
275 Delete(_) => {
305 Delete(_) => {
276− let start = pos_to_lsp_pos(&old_text, old_pos);
306+ let start = pos_to_lsp_pos(&new_text, new_pos);
277− let end = pos_to_lsp_pos(&old_text, old_end);
307+ let end = traverse(start, old_text.slice(old_pos..old_end));
279 // deletion
309 // deletion
280 changes.push(lsp::TextDocumentContentChangeEvent {
310 changes.push(lsp::TextDocumentContentChangeEvent {
@@ -284,12 +314,14 @@ impl Client {
286 Insert(s) => {
316 Insert(s) => {
287− let start = pos_to_lsp_pos(&old_text, old_pos);
317+ let start = pos_to_lsp_pos(&new_text, new_pos);
319+ new_pos += s.chars().count();
289 // a subsequent delete means a replace, consume it
321 // a subsequent delete means a replace, consume it
290 let end = if let Some(Delete(len)) = iter.peek() {
322 let end = if let Some(Delete(len)) = iter.peek() {
291 old_end = old_pos + len;
323 old_end = old_pos + len;
292− let end = pos_to_lsp_pos(&old_text, old_end);
324+ let end = traverse(start, old_text.slice(old_pos..old_end));
294 iter.next();
326 iter.next();
@@ -318,6 +350,7 @@ impl Client {
319 text_document: lsp::VersionedTextDocumentIdentifier,
351 text_document: lsp::VersionedTextDocumentIdentifier,
320 old_text: &Rope,
352 old_text: &Rope,
321 changes: &ChangeSet,
354 changes: &ChangeSet,
322 ) -> Result<()> {
355 ) -> Result<()> {
323 // figure out what kind of sync the server supports
356 // figure out what kind of sync the server supports
@@ -343,7 +376,9 @@ impl Client {
343 text: "".to_string(),
376 text: "".to_string(),
344 }] // TODO: probably need old_state here too?
377 }] // TODO: probably need old_state here too?
379+ lsp::TextDocumentSyncKind::Incremental => {
346− lsp::TextDocumentSyncKind::Incremental => Self::changeset_to_changes(old_text, changes),
380+ Self::changeset_to_changes(old_text, new_text, changes)
347 lsp::TextDocumentSyncKind::None => return Ok(()),
382 lsp::TextDocumentSyncKind::None => return Ok(()),