on master help sign in
Handle snippets for LSPs not providing offsets for completion
commit8c2e447b16e4d11db411b18f2fbe3ac2bc031d89 authorAndrii Grynenko <gluk.ua@gmail.com> dateThu 2 Mar 2023, 21:41 (4 years ago) parent0d92425
2 files changed+61−67
helix-lsp/src/lib.rs+7−26 helix-term/src/ui/completion.rs+54−41
helix-lsp/src/lib.rs+7−26
@@ -252,26 +252,17 @@ pub mod util {
252252 pub fn generate_transaction_from_completion_edit(
253253 doc: &Rope,
254254 selection: &Selection,
255− edit: lsp::TextEdit,
256− offset_encoding: OffsetEncoding,
255+ start_offset: i128,
256+ end_offset: i128,
257+ new_text: String,
257258 ) -> Transaction {
258− let replacement: Option<Tendril> = if edit.new_text.is_empty() {
259+ let replacement: Option<Tendril> = if new_text.is_empty() {
259260 None
260261 } else {
261− Some(edit.new_text.into())
262+ Some(new_text.into())
262263 };
263264
264265 let text = doc.slice(..);
265− let primary_cursor = selection.primary().cursor(text);
266−
267− let start_offset = match lsp_pos_to_pos(doc, edit.range.start, offset_encoding) {
268− Some(start) => start as i128 - primary_cursor as i128,
269− None => return Transaction::new(doc),
270− };
271− let end_offset = match lsp_pos_to_pos(doc, edit.range.end, offset_encoding) {
272− Some(end) => end as i128 - primary_cursor as i128,
273− None => return Transaction::new(doc),
274− };
275266
276267 Transaction::change_by_selection(doc, selection, |range| {
277268 let cursor = range.cursor(text);
@@ -288,23 +279,13 @@ pub mod util {
288279 pub fn generate_transaction_from_snippet(
289280 doc: &Rope,
290281 selection: &Selection,
291− edit_range: &lsp::Range,
282+ start_offset: i128,
283+ end_offset: i128,
292284 snippet: snippet::Snippet,
293285 line_ending: &str,
294286 include_placeholder: bool,
295− offset_encoding: OffsetEncoding,
296287 ) -> Transaction {
297288 let text = doc.slice(..);
298− let primary_cursor = selection.primary().cursor(text);
299−
300− let start_offset = match lsp_pos_to_pos(doc, edit_range.start, offset_encoding) {
301− Some(start) => start as i128 - primary_cursor as i128,
302− None => return Transaction::new(doc),
303− };
304− let end_offset = match lsp_pos_to_pos(doc, edit_range.end, offset_encoding) {
305− Some(end) => end as i128 - primary_cursor as i128,
306− None => return Transaction::new(doc),
307− };
308289
309290 // For each cursor store offsets for the first tabstop
310291 let mut cursor_tabstop_offsets = Vec::<SmallVec<[(i128, i128); 1]>>::new();
helix-term/src/ui/completion.rs+54−41
@@ -121,8 +121,9 @@ impl Completion {
121121 include_placeholder: bool,
122122 ) -> Transaction {
123123 use helix_lsp::snippet;
124+ let selection = doc.selection(view_id);
124125
125− if let Some(edit) = &item.text_edit {
126+ let (start_offset, end_offset, new_text) = if let Some(edit) = &item.text_edit {
126127 let edit = match edit {
127128 lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
128129 lsp::CompletionTextEdit::InsertAndReplace(item) => {
@@ -130,46 +131,27 @@ impl Completion {
130131 lsp::TextEdit::new(item.replace, item.new_text.clone())
131132 }
132133 };
133−
134− if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET))
135− || matches!(
136− item.insert_text_format,
137− Some(lsp::InsertTextFormat::SNIPPET)
138− )
139− {
140− match snippet::parse(&edit.new_text) {
141− Ok(snippet) => util::generate_transaction_from_snippet(
142− doc.text(),
143− doc.selection(view_id),
144− &edit.range,
145− snippet,
146− doc.line_ending.as_str(),
147− include_placeholder,
148− offset_encoding,
149− ),
150− Err(err) => {
151− log::error!(
152− "Failed to parse snippet: {:?}, remaining output: {}",
153− &edit.new_text,
154− err
155− );
156− Transaction::new(doc.text())
157− }
158− }
159− } else {
160− util::generate_transaction_from_completion_edit(
161− doc.text(),
162− doc.selection(view_id),
163− edit,
164− offset_encoding, // TODO: should probably transcode in Client
165− )
166− }
134+ let text = doc.text().slice(..);
135+ let primary_cursor = selection.primary().cursor(text);
136+
137+ let start_offset =
138+ match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) {
139+ Some(start) => start as i128 - primary_cursor as i128,
140+ None => return Transaction::new(doc.text()),
141+ };
142+ let end_offset =
143+ match util::lsp_pos_to_pos(doc.text(), edit.range.end, offset_encoding) {
144+ Some(end) => end as i128 - primary_cursor as i128,
145+ None => return Transaction::new(doc.text()),
146+ };
147+
148+ (start_offset, end_offset, edit.new_text)
167149 } else {
168− let text = item.insert_text.as_ref().unwrap_or(&item.label);
150+ let new_text = item.insert_text.as_ref().unwrap_or(&item.label);
169151 // Some LSPs just give you an insertText with no offset ¯\_(ツ)_/¯
170152 // in these cases we need to check for a common prefix and remove it
171153 let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset));
172− let text = text.trim_start_matches::<&str>(&prefix);
154+ let new_text = new_text.trim_start_matches::<&str>(&prefix);
173155
174156 // TODO: this needs to be true for the numbers to work out correctly
175157 // in the closure below. It's passed in to a callback as this same
@@ -182,11 +164,42 @@ impl Completion {
182164 == trigger_offset
183165 );
184166
185− Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
186− let cursor = range.cursor(doc.text().slice(..));
167+ (0, 0, new_text.into())
168+ };
187169
188− (cursor, cursor, Some(text.into()))
189− })
170+ if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET))
171+ || matches!(
172+ item.insert_text_format,
173+ Some(lsp::InsertTextFormat::SNIPPET)
174+ )
175+ {
176+ match snippet::parse(&new_text) {
177+ Ok(snippet) => util::generate_transaction_from_snippet(
178+ doc.text(),
179+ selection,
180+ start_offset,
181+ end_offset,
182+ snippet,
183+ doc.line_ending.as_str(),
184+ include_placeholder,
185+ ),
186+ Err(err) => {
187+ log::error!(
188+ "Failed to parse snippet: {:?}, remaining output: {}",
189+ &new_text,
190+ err
191+ );
192+ Transaction::new(doc.text())
193+ }
194+ }
195+ } else {
196+ util::generate_transaction_from_completion_edit(
197+ doc.text(),
198+ selection,
199+ start_offset,
200+ end_offset,
201+ new_text,
202+ )
190203 }
191204 }
192205