aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-08-10 05:12:57 +0000
committerBlaž Hrastnik2021-08-11 01:56:32 +0000
commit627b89931576f7af86166ae8d5cbc55537877473 (patch)
treed09fd9a08b3bfe40d462302dc20f0881dacedd9f /helix-term/src
parent6cd77ef380e1f87f5af613dbf63acac6b7fec47d (diff)
ui: completion: Insert suggestions when tabbing over them
Fixes #498
Diffstat (limited to 'helix-term/src')
-rw-r--r--helix-term/src/ui/completion.rs81
1 files changed, 56 insertions, 25 deletions
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index f359e7ec..6d737652 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -5,7 +5,7 @@ use tui::buffer::Buffer as Surface;
use std::borrow::Cow;
use helix_core::Transaction;
-use helix_view::{graphics::Rect, Editor};
+use helix_view::{graphics::Rect, Document, Editor, View};
use crate::commands;
use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
@@ -81,15 +81,47 @@ impl Completion {
) -> Self {
// let items: Vec<CompletionItem> = Vec::new();
let menu = Menu::new(items, move |editor: &mut Editor, item, event| {
+ fn item_to_transaction(
+ doc: &Document,
+ view: &View,
+ item: &CompletionItem,
+ offset_encoding: helix_lsp::OffsetEncoding,
+ ) -> Transaction {
+ if let Some(edit) = &item.text_edit {
+ let edit = match edit {
+ lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
+ lsp::CompletionTextEdit::InsertAndReplace(item) => {
+ unimplemented!("completion: insert_and_replace {:?}", item)
+ }
+ };
+ util::generate_transaction_from_edits(
+ doc.text(),
+ vec![edit],
+ offset_encoding, // TODO: should probably transcode in Client
+ )
+ } else {
+ let text = item.insert_text.as_ref().unwrap_or(&item.label);
+ let cursor = doc
+ .selection(view.id)
+ .primary()
+ .cursor(doc.text().slice(..));
+ Transaction::change(
+ doc.text(),
+ vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
+ )
+ }
+ }
+
match event {
PromptEvent::Abort => {}
- PromptEvent::Validate => {
+ PromptEvent::Update => {
let (view, doc) = current!(editor);
// always present here
let item = item.unwrap();
// if more text was entered, remove it
+ // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
let cursor = doc
.selection(view.id)
.primary()
@@ -102,30 +134,30 @@ impl Completion {
doc.apply(&remove, view.id);
}
- let transaction = if let Some(edit) = &item.text_edit {
- let edit = match edit {
- lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
- lsp::CompletionTextEdit::InsertAndReplace(item) => {
- unimplemented!("completion: insert_and_replace {:?}", item)
- }
- };
- util::generate_transaction_from_edits(
- doc.text(),
- vec![edit],
- offset_encoding, // TODO: should probably transcode in Client
- )
- } else {
- let text = item.insert_text.as_ref().unwrap_or(&item.label);
- let cursor = doc
- .selection(view.id)
- .primary()
- .cursor(doc.text().slice(..));
- Transaction::change(
+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
+ doc.apply(&transaction, view.id);
+ }
+ PromptEvent::Validate => {
+ let (view, doc) = current!(editor);
+
+ // always present here
+ let item = item.unwrap();
+
+ // if more text was entered, remove it
+ // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
+ let cursor = doc
+ .selection(view.id)
+ .primary()
+ .cursor(doc.text().slice(..));
+ if trigger_offset < cursor {
+ let remove = Transaction::change(
doc.text(),
- vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
- )
- };
+ vec![(trigger_offset, cursor, None)].into_iter(),
+ );
+ doc.apply(&remove, view.id);
+ }
+ let transaction = item_to_transaction(doc, view, item, offset_encoding);
doc.apply(&transaction, view.id);
if let Some(additional_edits) = &item.additional_text_edits {
@@ -140,7 +172,6 @@ impl Completion {
}
}
}
- _ => (),
};
});
let popup = Popup::new(menu);