Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply completion edits to all cursors #4496

Merged
merged 1 commit into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
///
Expand Down Expand Up @@ -195,6 +195,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>,
Expand Down
31 changes: 24 additions & 7 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -164,6 +179,7 @@ impl Completion {

let transaction = item_to_transaction(
doc,
view.id,
item,
offset_encoding,
start_offset,
Expand All @@ -185,6 +201,7 @@ impl Completion {

let transaction = item_to_transaction(
doc,
view.id,
item,
offset_encoding,
start_offset,
Expand Down