|
|
@ -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, Document, Editor, View};
|
|
|
|
use helix_view::{graphics::Rect, Document, Editor};
|
|
|
|
|
|
|
|
|
|
|
|
use crate::commands;
|
|
|
|
use crate::commands;
|
|
|
|
use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
|
|
|
|
use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
|
|
|
@ -83,13 +83,13 @@ impl Completion {
|
|
|
|
start_offset: usize,
|
|
|
|
start_offset: usize,
|
|
|
|
trigger_offset: usize,
|
|
|
|
trigger_offset: usize,
|
|
|
|
) -> Self {
|
|
|
|
) -> Self {
|
|
|
|
// 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(
|
|
|
|
fn item_to_transaction(
|
|
|
|
doc: &Document,
|
|
|
|
doc: &Document,
|
|
|
|
view: &View,
|
|
|
|
|
|
|
|
item: &CompletionItem,
|
|
|
|
item: &CompletionItem,
|
|
|
|
offset_encoding: helix_lsp::OffsetEncoding,
|
|
|
|
offset_encoding: helix_lsp::OffsetEncoding,
|
|
|
|
|
|
|
|
start_offset: usize,
|
|
|
|
|
|
|
|
trigger_offset: usize,
|
|
|
|
) -> Transaction {
|
|
|
|
) -> Transaction {
|
|
|
|
if let Some(edit) = &item.text_edit {
|
|
|
|
if let Some(edit) = &item.text_edit {
|
|
|
|
let edit = match edit {
|
|
|
|
let edit = match edit {
|
|
|
@ -105,63 +105,52 @@ impl Completion {
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
let text = item.insert_text.as_ref().unwrap_or(&item.label);
|
|
|
|
let text = item.insert_text.as_ref().unwrap_or(&item.label);
|
|
|
|
let cursor = doc
|
|
|
|
// Some LSPs just give you an insertText with no offset ¯\_(ツ)_/¯
|
|
|
|
.selection(view.id)
|
|
|
|
// in these cases we need to check for a common prefix and remove it
|
|
|
|
.primary()
|
|
|
|
let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset));
|
|
|
|
.cursor(doc.text().slice(..));
|
|
|
|
let text = text.trim_start_matches::<&str>(&prefix);
|
|
|
|
Transaction::change(
|
|
|
|
Transaction::change(
|
|
|
|
doc.text(),
|
|
|
|
doc.text(),
|
|
|
|
vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
|
|
|
|
vec![(trigger_offset, trigger_offset, Some(text.into()))].into_iter(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let (view, doc) = current!(editor);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if more text was entered, remove it
|
|
|
|
|
|
|
|
doc.restore(view.id);
|
|
|
|
|
|
|
|
|
|
|
|
match event {
|
|
|
|
match event {
|
|
|
|
PromptEvent::Abort => {}
|
|
|
|
PromptEvent::Abort => {}
|
|
|
|
PromptEvent::Update => {
|
|
|
|
PromptEvent::Update => {
|
|
|
|
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
|
|
|
|
let transaction = item_to_transaction(
|
|
|
|
// TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
|
|
|
|
doc,
|
|
|
|
let cursor = doc
|
|
|
|
item,
|
|
|
|
.selection(view.id)
|
|
|
|
offset_encoding,
|
|
|
|
.primary()
|
|
|
|
start_offset,
|
|
|
|
.cursor(doc.text().slice(..));
|
|
|
|
trigger_offset,
|
|
|
|
if trigger_offset < cursor {
|
|
|
|
|
|
|
|
let remove = Transaction::change(
|
|
|
|
|
|
|
|
doc.text(),
|
|
|
|
|
|
|
|
vec![(trigger_offset, cursor, None)].into_iter(),
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
doc.apply(&remove, view.id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let transaction = item_to_transaction(doc, view, item, offset_encoding);
|
|
|
|
// initialize a savepoint
|
|
|
|
|
|
|
|
doc.savepoint();
|
|
|
|
|
|
|
|
|
|
|
|
doc.apply(&transaction, view.id);
|
|
|
|
doc.apply(&transaction, view.id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PromptEvent::Validate => {
|
|
|
|
PromptEvent::Validate => {
|
|
|
|
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
|
|
|
|
let transaction = item_to_transaction(
|
|
|
|
// TODO: ideally to undo we should keep the last completion tx revert, and map it over new changes
|
|
|
|
doc,
|
|
|
|
let cursor = doc
|
|
|
|
item,
|
|
|
|
.selection(view.id)
|
|
|
|
offset_encoding,
|
|
|
|
.primary()
|
|
|
|
start_offset,
|
|
|
|
.cursor(doc.text().slice(..));
|
|
|
|
trigger_offset,
|
|
|
|
if trigger_offset < cursor {
|
|
|
|
|
|
|
|
let remove = Transaction::change(
|
|
|
|
|
|
|
|
doc.text(),
|
|
|
|
|
|
|
|
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 {
|
|
|
|