@@ -5,7 +5,7 @@ use tui::buffer::Buffer as Surface;
55use std::borrow::Cow;
66
77use helix_core::Transaction;
8−use helix_view::{graphics::Rect, Editor};
8+use helix_view::{graphics::Rect, Document, Editor, View};
99
1010use crate::commands;
1111use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
@@ -81,15 +81,47 @@ impl Completion {
8181 ) -> Self {
8282 // let items: Vec<CompletionItem> = Vec::new();
8383 let menu = Menu::new(items, move |editor: &mut Editor, item, event| {
84+ fn item_to_transaction(
85+ doc: &Document,
86+ view: &View,
87+ item: &CompletionItem,
88+ offset_encoding: helix_lsp::OffsetEncoding,
89+ ) -> Transaction {
90+ if let Some(edit) = &item.text_edit {
91+ let edit = match edit {
92+ lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
93+ lsp::CompletionTextEdit::InsertAndReplace(item) => {
94+ unimplemented!("completion: insert_and_replace {:?}", item)
95+ }
96+ };
97+ util::generate_transaction_from_edits(
98+ doc.text(),
99+ vec![edit],
100+ offset_encoding, // TODO: should probably transcode in Client
101+ )
102+ } else {
103+ let text = item.insert_text.as_ref().unwrap_or(&item.label);
104+ let cursor = doc
105+ .selection(view.id)
106+ .primary()
107+ .cursor(doc.text().slice(..));
108+ Transaction::change(
109+ doc.text(),
110+ vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
111+ )
112+ }
113+ }
114+
84115 match event {
85116 PromptEvent::Abort => {}
86− PromptEvent::Validate => {
117+ PromptEvent::Update => {
87118 let (view, doc) = current!(editor);
88119
89120 // always present here
90121 let item = item.unwrap();
91122
92123 // if more text was entered, remove it
124+ // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
93125 let cursor = doc
94126 .selection(view.id)
95127 .primary()
@@ -102,30 +134,30 @@ impl Completion {
102134 doc.apply(&remove, view.id);
103135 }
104136
105− let transaction = if let Some(edit) = &item.text_edit {
106− let edit = match edit {
107− lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
108− lsp::CompletionTextEdit::InsertAndReplace(item) => {
109− unimplemented!("completion: insert_and_replace {:?}", item)
110− }
111− };
112− util::generate_transaction_from_edits(
113− doc.text(),
114− vec![edit],
115− offset_encoding, // TODO: should probably transcode in Client
116− )
117− } else {
118− let text = item.insert_text.as_ref().unwrap_or(&item.label);
119− let cursor = doc
120− .selection(view.id)
121− .primary()
122− .cursor(doc.text().slice(..));
123− Transaction::change(
137+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
138+ doc.apply(&transaction, view.id);
139+ }
140+ PromptEvent::Validate => {
141+ let (view, doc) = current!(editor);
142+
143+ // always present here
144+ let item = item.unwrap();
145+
146+ // if more text was entered, remove it
147+ // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
148+ let cursor = doc
149+ .selection(view.id)
150+ .primary()
151+ .cursor(doc.text().slice(..));
152+ if trigger_offset < cursor {
153+ let remove = Transaction::change(
124154 doc.text(),
125− vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
126− )
127− };
155+ vec![(trigger_offset, cursor, None)].into_iter(),
156+ );
157+ doc.apply(&remove, view.id);
158+ }
128159
160+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
129161 doc.apply(&transaction, view.id);
130162
131163 if let Some(additional_edits) = &item.additional_text_edits {
@@ -140,7 +172,6 @@ impl Completion {
140172 }
141173 }
142174 }
143− _ => (),
144175 };
145176 });
146177 let popup = Popup::new(menu);