aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-lsp/src/lib.rs38
-rw-r--r--helix-term/src/ui/completion.rs31
2 files changed, 61 insertions, 8 deletions
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index abc930f8..f714395f 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -57,7 +57,7 @@ pub enum OffsetEncoding {
pub mod util {
use super::*;
- use helix_core::{diagnostic::NumberOrString, Range, Rope, Transaction};
+ use helix_core::{diagnostic::NumberOrString, Range, Rope, Selection, Tendril, Transaction};
/// Converts a diagnostic in the document to [`lsp::Diagnostic`].
///
@@ -196,6 +196,42 @@ pub mod util {
Some(Range::new(start, end))
}
+ /// Creates a [Transaction] from the [lsp::TextEdit] in a completion response.
+ /// The transaction applies the edit to all cursors.
+ pub fn generate_transaction_from_completion_edit(
+ doc: &Rope,
+ selection: &Selection,
+ edit: lsp::TextEdit,
+ offset_encoding: OffsetEncoding,
+ ) -> Transaction {
+ let replacement: Option<Tendril> = if edit.new_text.is_empty() {
+ None
+ } else {
+ Some(edit.new_text.into())
+ };
+
+ let text = doc.slice(..);
+ let primary_cursor = selection.primary().cursor(text);
+
+ let start_offset = match lsp_pos_to_pos(doc, edit.range.start, offset_encoding) {
+ Some(start) => start as i128 - primary_cursor as i128,
+ None => return Transaction::new(doc),
+ };
+ let end_offset = match lsp_pos_to_pos(doc, edit.range.end, offset_encoding) {
+ Some(end) => end as i128 - primary_cursor as i128,
+ None => return Transaction::new(doc),
+ };
+
+ Transaction::change_by_selection(doc, selection, |range| {
+ let cursor = range.cursor(text);
+ (
+ (cursor as i128 + start_offset) as usize,
+ (cursor as i128 + end_offset) as usize,
+ replacement.clone(),
+ )
+ })
+ }
+
pub fn generate_transaction_from_edits(
doc: &Rope,
mut edits: Vec<lsp::TextEdit>,
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index ebb4fb46..c54990e8 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -1,5 +1,5 @@
use crate::compositor::{Component, Context, Event, EventResult};
-use helix_view::{apply_transaction, editor::CompleteAction};
+use helix_view::{apply_transaction, editor::CompleteAction, ViewId};
use tui::buffer::Buffer as Surface;
use tui::text::Spans;
@@ -107,6 +107,7 @@ impl Completion {
let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| {
fn item_to_transaction(
doc: &Document,
+ view_id: ViewId,
item: &CompletionItem,
offset_encoding: helix_lsp::OffsetEncoding,
start_offset: usize,
@@ -121,9 +122,10 @@ impl Completion {
}
};
- util::generate_transaction_from_edits(
+ util::generate_transaction_from_completion_edit(
doc.text(),
- vec![edit],
+ doc.selection(view_id),
+ edit,
offset_encoding, // TODO: should probably transcode in Client
)
} else {
@@ -132,10 +134,23 @@ impl Completion {
// in these cases we need to check for a common prefix and remove it
let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset));
let text = text.trim_start_matches::<&str>(&prefix);
- Transaction::change(
- doc.text(),
- vec![(trigger_offset, trigger_offset, Some(text.into()))].into_iter(),
- )
+
+ // TODO: this needs to be true for the numbers to work out correctly
+ // in the closure below. It's passed in to a callback as this same
+ // formula, but can the value change between the LSP request and
+ // response? If it does, can we recover?
+ debug_assert!(
+ doc.selection(view_id)
+ .primary()
+ .cursor(doc.text().slice(..))
+ == trigger_offset
+ );
+
+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
+ let cursor = range.cursor(doc.text().slice(..));
+
+ (cursor, cursor, Some(text.into()))
+ })
};
transaction
@@ -164,6 +179,7 @@ impl Completion {
let transaction = item_to_transaction(
doc,
+ view.id,
item,
offset_encoding,
start_offset,
@@ -185,6 +201,7 @@ impl Completion {
let transaction = item_to_transaction(
doc,
+ view.id,
item,
offset_encoding,
start_offset,