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

feat: code actions - document edits #478

Merged
merged 18 commits into from
Jul 24, 2021
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
feat(term): applying code actions edits
  • Loading branch information
gbaranski committed Jul 21, 2021
commit 70db2f140dbbc5f6b45511bbea3a66a57a271004
114 changes: 66 additions & 48 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use helix_core::{
object, pos_at_coords,
regex::{self, Regex},
register::Register,
search, selection, surround, textobject, ChangeSet, LineEnding, Position, Range, Rope,
search, selection, surround, textobject, Change, LineEnding, Position, Range, Rope,
RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril, Transaction,
};

Expand Down Expand Up @@ -2130,14 +2130,41 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
)
}

fn apply_edit(
editor: &mut Editor,
edited_document: &lsp::OptionalVersionedTextDocumentIdentifier,
offset_encoding: OffsetEncoding,
edit: &lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit>,
) {
let (view, doc) = current!(editor);
assert_eq!(doc.url().unwrap(), edited_document.uri);

match edit {
lsp::OneOf::Left(text_edit) => {
let lsp_pos_to_pos =
|lsp_pos| lsp_pos_to_pos(doc.text(), lsp_pos, offset_encoding).unwrap();

// This clone probably could be optimized if Picker::new would give T instead of &T
let text_replacement = Tendril::from(text_edit.new_text.clone());
let change: Change = (
lsp_pos_to_pos(text_edit.range.start),
lsp_pos_to_pos(text_edit.range.end),
Some(text_replacement.clone().into()),
);
let transaction = Transaction::change(doc.text(), std::iter::once(change));
doc.apply(&transaction, view.id);
}
lsp::OneOf::Right(_annotated_text_edit) => todo!(),
}
}

pub fn code_action(cx: &mut Context) {
let (view, doc) = current!(cx.editor);

let language_server = match doc.language_server() {
Some(language_server) => language_server,
None => return,
};
let offset_encoding = language_server.offset_encoding();

let range = range_to_lsp_range(
doc.text(),
Expand All @@ -2146,10 +2173,11 @@ pub fn code_action(cx: &mut Context) {
);

let future = language_server.code_actions(doc.identifier(), range);
let offset_encoding = language_server.offset_encoding().clone();

cx.callback(
future,
move |editor: &mut Editor,
move |_editor: &mut Editor,
compositor: &mut Compositor,
response: Option<lsp::CodeActionResponse>| {
if let Some(actions) = response {
Expand All @@ -2162,51 +2190,7 @@ pub fn code_action(cx: &mut Context) {
lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(),
},
move |editor: &mut Editor, code_action, _action| {
match code_action {
lsp::CodeActionOrCommand::Command(command) => {
log::debug!("command: {:?}", command);
}
lsp::CodeActionOrCommand::CodeAction(code_action) => {
log::debug!("code action: {:?}", code_action);
if let Some(ref edit) = code_action.edit {
if let Some(ref changes) = edit.document_changes {
match changes {
lsp::DocumentChanges::Edits(document_edits) => {
for document_edit in document_edits {
for edit in &document_edit.edits {
match edit {
lsp::OneOf::Left(text_edit) => {
let document = editor
.documents()
.find(|doc| {
doc.url().as_ref()
== Some(
&document_edit
.text_document
.uri,
)
})
.unwrap();

let transaction = Transaction {
changes: todo!(),
selection: todo!(),
};
}
lsp::OneOf::Right(
annotated_text_edit,
) => todo!(),
}
}
}
}
lsp::DocumentChanges::Operations(_) => todo!(),
}
}
}
}
}
//
make_code_action_callback(editor, code_action, offset_encoding)
},
);
compositor.push(Box::new(picker))
Expand All @@ -2215,6 +2199,40 @@ pub fn code_action(cx: &mut Context) {
)
}

fn make_code_action_callback(
editor: &mut Editor,
code_action: &lsp::CodeActionOrCommand,
offset_encoding: OffsetEncoding,
) {
match code_action {
lsp::CodeActionOrCommand::Command(command) => {
log::debug!("command: {:?}", command);
}
lsp::CodeActionOrCommand::CodeAction(code_action) => {
log::debug!("code action: {:?}", code_action);
if let Some(ref edit) = code_action.edit {
if let Some(ref changes) = edit.document_changes {
match changes {
lsp::DocumentChanges::Edits(document_edits) => {
for document_edit in document_edits {
for edit in &document_edit.edits {
apply_edit(
editor,
&document_edit.text_document,
offset_encoding,
edit,
);
}
}
}
lsp::DocumentChanges::Operations(_) => todo!(),
}
}
}
}
}
}

// I inserts at the first nonwhitespace character of each line with a selection
fn prepend_to_line(cx: &mut Context) {
goto_first_nonwhitespace(cx);
Expand Down