From 8c2e447b16e4d11db411b18f2fbe3ac2bc031d89 Mon Sep 17 00:00:00 2001 From: Andrii Grynenko Date: Thu, 2 Mar 2023 21:41:06 -0800 Subject: Handle snippets for LSPs not providing offsets for completion --- helix-term/src/ui/completion.rs | 95 +++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 41 deletions(-) (limited to 'helix-term') diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index e7815e12..85931fe3 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -121,8 +121,9 @@ impl Completion { include_placeholder: bool, ) -> Transaction { use helix_lsp::snippet; + let selection = doc.selection(view_id); - if let Some(edit) = &item.text_edit { + let (start_offset, end_offset, new_text) = if let Some(edit) = &item.text_edit { let edit = match edit { lsp::CompletionTextEdit::Edit(edit) => edit.clone(), lsp::CompletionTextEdit::InsertAndReplace(item) => { @@ -130,46 +131,27 @@ impl Completion { lsp::TextEdit::new(item.replace, item.new_text.clone()) } }; - - if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET)) - || matches!( - item.insert_text_format, - Some(lsp::InsertTextFormat::SNIPPET) - ) - { - match snippet::parse(&edit.new_text) { - Ok(snippet) => util::generate_transaction_from_snippet( - doc.text(), - doc.selection(view_id), - &edit.range, - snippet, - doc.line_ending.as_str(), - include_placeholder, - offset_encoding, - ), - Err(err) => { - log::error!( - "Failed to parse snippet: {:?}, remaining output: {}", - &edit.new_text, - err - ); - Transaction::new(doc.text()) - } - } - } else { - util::generate_transaction_from_completion_edit( - doc.text(), - doc.selection(view_id), - edit, - offset_encoding, // TODO: should probably transcode in Client - ) - } + let text = doc.text().slice(..); + let primary_cursor = selection.primary().cursor(text); + + let start_offset = + match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) { + Some(start) => start as i128 - primary_cursor as i128, + None => return Transaction::new(doc.text()), + }; + let end_offset = + match util::lsp_pos_to_pos(doc.text(), edit.range.end, offset_encoding) { + Some(end) => end as i128 - primary_cursor as i128, + None => return Transaction::new(doc.text()), + }; + + (start_offset, end_offset, edit.new_text) } else { - let text = item.insert_text.as_ref().unwrap_or(&item.label); + let new_text = item.insert_text.as_ref().unwrap_or(&item.label); // Some LSPs just give you an insertText with no offset ¯\_(ツ)_/¯ // in these cases we need to check for a common prefix and remove it let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset)); - let text = text.trim_start_matches::<&str>(&prefix); + let new_text = new_text.trim_start_matches::<&str>(&prefix); // TODO: this needs to be true for the numbers to work out correctly // in the closure below. It's passed in to a callback as this same @@ -182,11 +164,42 @@ impl Completion { == trigger_offset ); - Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| { - let cursor = range.cursor(doc.text().slice(..)); + (0, 0, new_text.into()) + }; - (cursor, cursor, Some(text.into())) - }) + if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET)) + || matches!( + item.insert_text_format, + Some(lsp::InsertTextFormat::SNIPPET) + ) + { + match snippet::parse(&new_text) { + Ok(snippet) => util::generate_transaction_from_snippet( + doc.text(), + selection, + start_offset, + end_offset, + snippet, + doc.line_ending.as_str(), + include_placeholder, + ), + Err(err) => { + log::error!( + "Failed to parse snippet: {:?}, remaining output: {}", + &new_text, + err + ); + Transaction::new(doc.text()) + } + } + } else { + util::generate_transaction_from_completion_edit( + doc.text(), + selection, + start_offset, + end_offset, + new_text, + ) } } -- cgit v1.2.3-70-g09d2