@@ -1,6 +1,7 @@
11use std::borrow::Cow;
22
33use anyhow::{anyhow, Result};
4+use helix_core::SmallVec;
45
56use crate::{util::lsp_pos_to_pos, OffsetEncoding};
67
@@ -87,7 +88,7 @@ pub fn into_transaction<'a>(
8788
8889 let mut insert = String::new();
8990 let mut offset = (primary_cursor as i128 + start_offset) as usize;
90− let mut tabstops: Vec<Range> = Vec::new();
91+ let mut tabstops: Vec<(usize, Range)> = Vec::new();
9192
9293 for element in snippet.elements {
9394 match element {
@@ -111,20 +112,15 @@ pub fn into_transaction<'a>(
111112 offset += text.chars().count();
112113 insert.push_str(text);
113114 }
114− Tabstop { .. } => {
115− // TODO: tabstop indexing: 0 is final cursor position. 1,2,.. are positions.
116− // TODO: merge tabstops with the same index
117− tabstops.push(Range::point(offset));
115+ Tabstop { tabstop } => {
116+ tabstops.push((tabstop, Range::point(offset)));
118117 }
119− Placeholder {
120− tabstop: _tabstop,
121− value,
122− } => match value.as_ref() {
118+ Placeholder { tabstop, value } => match value.as_ref() {
123119 // https://doc.rust-lang.org/beta/unstable-book/language-features/box-patterns.html
124120 // would make this a bit nicer
125121 Text(text) => {
126122 let len_chars = text.chars().count();
127− tabstops.push(Range::new(offset, offset + len_chars + 1));
123+ tabstops.push((tabstop, Range::new(offset, offset + len_chars + 1)));
128124 offset += len_chars;
129125 insert.push_str(text);
130126 }
@@ -155,8 +151,25 @@ pub fn into_transaction<'a>(
155151 )
156152 });
157153
158− if let Some(first) = tabstops.first() {
159− transaction.with_selection(Selection::new(smallvec![*first], 0))
154+ // sort in ascending order (except for 0, which should always be the last one (per lsp doc))
155+ tabstops.sort_unstable_by_key(|(n, _range)| if *n == 0 { usize::MAX } else { *n });
156+
157+ // merge tabstops with the same index (we take advantage of the fact that we just sorted them
158+ // above to simply look backwards)
159+ let mut ntabstops = Vec::<SmallVec<[Range; 1]>>::new();
160+ let mut prev = None;
161+ for (tabstop, range) in tabstops {
162+ if prev == Some(tabstop) {
163+ let len_1 = ntabstops.len() - 1;
164+ ntabstops[len_1].push(range);
165+ } else {
166+ prev = Some(tabstop);
167+ ntabstops.push(smallvec![range]);
168+ }
169+ }
170+
171+ if let Some(first) = ntabstops.first() {
172+ transaction.with_selection(Selection::new(first.clone(), 0))
160173 } else {
161174 transaction
162175 }