@@ -124,6 +124,8 @@ impl Completion {
124 ) -> Transaction {
124 ) -> Transaction {
125 use helix_lsp::snippet;
125 use helix_lsp::snippet;
126 let selection = doc.selection(view_id);
126 let selection = doc.selection(view_id);
127+ let text = doc.text().slice(..);
128+ let primary_cursor = selection.primary().cursor(text);
128 let (start_offset, end_offset, new_text) = if let Some(edit) = &item.text_edit {
130 let (start_offset, end_offset, new_text) = if let Some(edit) = &item.text_edit {
129 let edit = match edit {
131 let edit = match edit {
@@ -133,8 +135,6 @@ impl Completion {
133 lsp::TextEdit::new(item.replace, item.new_text.clone())
135 lsp::TextEdit::new(item.replace, item.new_text.clone())
136− let text = doc.text().slice(..);
137− let primary_cursor = selection.primary().cursor(text);
139 let start_offset =
139 let start_offset =
140 match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) {
140 match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) {
@@ -149,24 +149,26 @@ impl Completion {
150 (start_offset, end_offset, edit.new_text)
150 (start_offset, end_offset, edit.new_text)
152− let new_text = item.insert_text.as_ref().unwrap_or(&item.label);
152+ let new_text = item
153− // Some LSPs just give you an insertText with no offset ¯\_(ツ)_/¯
153+ .insert_text
154− // in these cases we need to check for a common prefix and remove it
154+ .clone()
155− let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset));
155+ .unwrap_or_else(|| item.label.clone());
156− let new_text = new_text.trim_start_matches::<&str>(&prefix);
156+
157−
157+ // check that we are still at the correct savepoint
158− // TODO: this needs to be true for the numbers to work out correctly
158+ // we can still generate a transaction regardless but if the
159− // in the closure below. It's passed in to a callback as this same
159+ // document changed (and not just the selection) then we will
160− // formula, but can the value change between the LSP request and
160+ // likely delete the wrong text (same if we applied an edit sent by the LS)
161− // response? If it does, can we recover?
162− debug_assert!(
161+ debug_assert!(primary_cursor == trigger_offset);
163− doc.selection(view_id)
162+
164− .primary()
163+ // TODO: Respect editor.completion_replace?
165− .cursor(doc.text().slice(..))
164+ // Would require detecting the end of the word boundary for every cursor individually.
166− == trigger_offset
165+ // We don't do the same for normal `edits, to be consistent we would have to do it for those too
168+ start_offset as i128 - primary_cursor as i128,
169+ trigger_offset as i128 - primary_cursor as i128,
169− (0, 0, new_text.into())
170+ new_text,
172 if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET))
174 if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET))