on master help sign in
ui: completion: Insert suggestions when tabbing over them
627b899Blaž Hrastnik
helix-term/src/ui/completion.rs+56−25
@@ -5,7 +5,7 @@ use tui::buffer::Buffer as Surface;
5use std::borrow::Cow;
5use std::borrow::Cow;
6
6
7use helix_core::Transaction;
7use helix_core::Transaction;
8−use helix_view::{graphics::Rect, Editor};
8+use helix_view::{graphics::Rect, Document, Editor, View};
9
9
10use crate::commands;
10use crate::commands;
11use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
11use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
@@ -81,15 +81,47 @@ impl Completion {
81 ) -> Self {
81 ) -> Self {
82 // let items: Vec<CompletionItem> = Vec::new();
82 // let items: Vec<CompletionItem> = Vec::new();
83 let menu = Menu::new(items, move |editor: &mut Editor, item, event| {
83 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+
84 match event {
115 match event {
85 PromptEvent::Abort => {}
116 PromptEvent::Abort => {}
86− PromptEvent::Validate => {
117+ PromptEvent::Update => {
87 let (view, doc) = current!(editor);
118 let (view, doc) = current!(editor);
88
119
89 // always present here
120 // always present here
90 let item = item.unwrap();
121 let item = item.unwrap();
91
122
92 // if more text was entered, remove it
123 // 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
93 let cursor = doc
125 let cursor = doc
94 .selection(view.id)
126 .selection(view.id)
95 .primary()
127 .primary()
@@ -102,30 +134,30 @@ impl Completion {
102 doc.apply(&remove, view.id);
134 doc.apply(&remove, view.id);
103 }
135 }
104
136
105− let transaction = if let Some(edit) = &item.text_edit {
137+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
106− let edit = match edit {
138+ doc.apply(&transaction, view.id);
107− lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
139+ }
108− lsp::CompletionTextEdit::InsertAndReplace(item) => {
140+ PromptEvent::Validate => {
109− unimplemented!("completion: insert_and_replace {:?}", item)
141+ let (view, doc) = current!(editor);
110− }
142+
111− };
143+ // always present here
112− util::generate_transaction_from_edits(
144+ let item = item.unwrap();
113− doc.text(),
145+
114− vec![edit],
146+ // if more text was entered, remove it
115− offset_encoding, // TODO: should probably transcode in Client
147+ // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
116− )
117− } else {
118− let text = item.insert_text.as_ref().unwrap_or(&item.label);
119− let cursor = doc
148+ let cursor = doc
120− .selection(view.id)
149+ .selection(view.id)
121− .primary()
150+ .primary()
122− .cursor(doc.text().slice(..));
151+ .cursor(doc.text().slice(..));
152+ if trigger_offset < cursor {
123− Transaction::change(
153+ let remove = Transaction::change(
124 doc.text(),
154 doc.text(),
125− vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
155+ vec![(trigger_offset, cursor, None)].into_iter(),
126− )
156+ );
157+ doc.apply(&remove, view.id);
127− };
158+ }
128
159
160+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
129 doc.apply(&transaction, view.id);
161 doc.apply(&transaction, view.id);
130
162
131 if let Some(additional_edits) = &item.additional_text_edits {
163 if let Some(additional_edits) = &item.additional_text_edits {
@@ -140,7 +172,6 @@ impl Completion {
140 }
172 }
141 }
173 }
142 }
174 }
143− _ => (),
144 };
175 };
145 });
176 });
146 let popup = Popup::new(menu);
177 let popup = Popup::new(menu);