ui: completion: Insert suggestions when tabbing over them

Fixes #498
pull/572/head
Blaž Hrastnik 3 years ago
parent 6cd77ef380
commit 627b899315

@ -5,7 +5,7 @@ use tui::buffer::Buffer as Surface;
use std::borrow::Cow; use std::borrow::Cow;
use helix_core::Transaction; use helix_core::Transaction;
use helix_view::{graphics::Rect, Editor}; use helix_view::{graphics::Rect, Document, Editor, View};
use crate::commands; use crate::commands;
use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent}; use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
@ -81,15 +81,47 @@ impl Completion {
) -> Self { ) -> Self {
// let items: Vec<CompletionItem> = Vec::new(); // let items: Vec<CompletionItem> = Vec::new();
let menu = Menu::new(items, move |editor: &mut Editor, item, event| { 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 { match event {
PromptEvent::Abort => {} PromptEvent::Abort => {}
PromptEvent::Validate => { PromptEvent::Update => {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
// always present here // always present here
let item = item.unwrap(); let item = item.unwrap();
// if more text was entered, remove it // 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 let cursor = doc
.selection(view.id) .selection(view.id)
.primary() .primary()
@ -102,30 +134,30 @@ impl Completion {
doc.apply(&remove, view.id); doc.apply(&remove, view.id);
} }
let transaction = if let Some(edit) = &item.text_edit { let transaction = item_to_transaction(doc, view, item, offset_encoding);
let edit = match edit { doc.apply(&transaction, view.id);
lsp::CompletionTextEdit::Edit(edit) => edit.clone(), }
lsp::CompletionTextEdit::InsertAndReplace(item) => { PromptEvent::Validate => {
unimplemented!("completion: insert_and_replace {:?}", item) let (view, doc) = current!(editor);
}
}; // always present here
util::generate_transaction_from_edits( let item = item.unwrap();
doc.text(),
vec![edit], // if more text was entered, remove it
offset_encoding, // TODO: should probably transcode in Client // TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
) let cursor = doc
} else { .selection(view.id)
let text = item.insert_text.as_ref().unwrap_or(&item.label); .primary()
let cursor = doc .cursor(doc.text().slice(..));
.selection(view.id) if trigger_offset < cursor {
.primary() let remove = Transaction::change(
.cursor(doc.text().slice(..));
Transaction::change(
doc.text(), 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); doc.apply(&transaction, view.id);
if let Some(additional_edits) = &item.additional_text_edits { if let Some(additional_edits) = &item.additional_text_edits {
@ -140,7 +172,6 @@ impl Completion {
} }
} }
} }
_ => (),
}; };
}); });
let popup = Popup::new(menu); let popup = Popup::new(menu);

Loading…
Cancel
Save