Skip to content

Commit

Permalink
Refactor sync
Browse files Browse the repository at this point in the history
  • Loading branch information
jpttrssn committed Sep 7, 2024
1 parent 498c525 commit 393de46
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 77 deletions.
48 changes: 40 additions & 8 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::lsp::{
};
use helix_core::{find_workspace, syntax::LanguageServerFeature, ChangeSet, Rope};
use helix_loader::VERSION_AND_GIT_HASH;
use helix_lsp_types::TextDocumentContentChangeEvent;
use helix_stdx::path;
use parking_lot::Mutex;
use serde::Deserialize;
Expand Down Expand Up @@ -951,7 +952,45 @@ impl Client {
old_text: &Rope,
new_text: &Rope,
changes: &ChangeSet,
) -> Option<impl Future<Output = Result<()>>> {
if let Some(changes) = self.text_document_did_change_impl(old_text, new_text, changes) {
return Some(self.notify::<lsp::notification::DidChangeTextDocument>(
lsp::DidChangeTextDocumentParams {
text_document,
content_changes: changes,
},
));
};
None
}

/// Will send textDocument/didChange notificaiton synchronously
pub fn text_document_did_change_sync(
&self,
text_document: lsp::VersionedTextDocumentIdentifier,
old_text: &Rope,
new_text: &Rope,
changes: &ChangeSet,
) -> Option<Result<()>> {
if let Some(changes) = self.text_document_did_change_impl(old_text, new_text, changes) {
return Some(
self.notify_sync::<lsp::notification::DidChangeTextDocument>(
lsp::DidChangeTextDocumentParams {
text_document,
content_changes: changes,
},
),
);
};
None
}

pub fn text_document_did_change_impl(
&self,
old_text: &Rope,
new_text: &Rope,
changes: &ChangeSet,
) -> Option<Vec<TextDocumentContentChangeEvent>> {
let capabilities = self.capabilities.get().unwrap();

// Return early if the server does not support document sync.
Expand Down Expand Up @@ -983,14 +1022,7 @@ impl Client {
kind => unimplemented!("{:?}", kind),
};

Some(
self.notify_sync::<lsp::notification::DidChangeTextDocument>(
lsp::DidChangeTextDocumentParams {
text_document,
content_changes: changes,
},
),
)
Some(changes)
}

pub fn text_document_did_close(
Expand Down
122 changes: 81 additions & 41 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,11 @@ struct CodeActionOrCommandItem {
language_server_id: LanguageServerId,
}

struct CodeActionItem {
lsp_item: lsp::CodeAction,
language_server_id: LanguageServerId,
}

impl ui::menu::Item for CodeActionOrCommandItem {
type Data = ();
fn format(&self, _data: &Self::Data) -> Row {
Expand Down Expand Up @@ -712,8 +717,36 @@ pub fn code_action(cx: &mut Context) {

// always present here
let action = action.unwrap();
let Some(language_server) = editor.language_server_by_id(action.language_server_id)
else {
editor.set_error("Language Server disappeared");
return;
};
let offset_encoding = language_server.offset_encoding();

apply_code_action(editor, action);
match &action.lsp_item {
lsp::CodeActionOrCommand::Command(command) => {
log::debug!("code action command: {:?}", command);
execute_lsp_command(editor, action.language_server_id, command.clone());
}
lsp::CodeActionOrCommand::CodeAction(code_action) => {
log::debug!("code action: {:?}", code_action);
let resolved_code_action =
resolve_code_action(code_action, language_server);

if let Some(ref workspace_edit) =
resolved_code_action.as_ref().unwrap_or(code_action).edit
{
let _ = editor.apply_workspace_edit(offset_encoding, workspace_edit);
}

// if code action provides both edit and command first the edit
// should be applied and then the command
if let Some(command) = &code_action.command {
execute_lsp_command(editor, action.language_server_id, command.clone());
}
}
}
});
picker.move_down(); // pre-select the first item

Expand Down Expand Up @@ -780,7 +813,7 @@ pub fn code_actions_on_save(cx: &mut compositor::Context, doc_id: &DocumentId) {
log::debug!("Attempting code action on save {:?}", code_action_kind);
let doc = doc!(cx.editor, doc_id);
let full_range = Range::new(0, doc.text().len_chars());
let code_actions: Vec<CodeActionOrCommandItem> =
let code_actions: Vec<CodeActionItem> =
code_actions_for_range(doc, full_range, Some(vec![code_action_kind.clone()]))
.into_iter()
.filter_map(|(future, language_server_id)| {
Expand Down Expand Up @@ -808,10 +841,15 @@ pub fn code_actions_on_save(cx: &mut compositor::Context, doc_id: &DocumentId) {

// Use the first matching code action
if let Some(lsp_item) = actions.first() {
return Some(CodeActionOrCommandItem {
lsp_item: lsp_item.clone(),
language_server_id,
});
return match lsp_item {
CodeActionOrCommand::CodeAction(code_action) => {
Some(CodeActionItem {
lsp_item: code_action.clone(),
language_server_id,
})
}
_ => None,
};
}
}
}
Expand All @@ -831,50 +869,52 @@ pub fn code_actions_on_save(cx: &mut compositor::Context, doc_id: &DocumentId) {
code_action.lsp_item,
code_action.language_server_id
);
apply_code_action(cx.editor, &code_action);
let Some(language_server) = cx
.editor
.language_server_by_id(code_action.language_server_id)
else {
log::error!(
"Language server disappeared {:?}",
code_action.language_server_id
);
continue;
};

let offset_encoding = language_server.offset_encoding();

let resolved_code_action =
resolve_code_action(&code_action.lsp_item, language_server);

if let Some(ref workspace_edit) = resolved_code_action
.as_ref()
.unwrap_or(&code_action.lsp_item)
.edit
{
let _ = cx
.editor
.apply_workspace_edit_sync(offset_encoding, workspace_edit);
}
}
}
}
}

fn apply_code_action(editor: &mut Editor, action: &CodeActionOrCommandItem) {
let Some(language_server) = editor.language_server_by_id(action.language_server_id) else {
editor.set_error("Language Server disappeared");
return;
};
let offset_encoding = language_server.offset_encoding();

match &action.lsp_item {
lsp::CodeActionOrCommand::Command(command) => {
log::debug!("code action command: {:?}", command);
execute_lsp_command(editor, action.language_server_id, command.clone());
}
lsp::CodeActionOrCommand::CodeAction(code_action) => {
log::debug!("code action: {:?}", code_action);
// we support lsp "codeAction/resolve" for `edit` and `command` fields
let mut resolved_code_action = None;
if code_action.edit.is_none() || code_action.command.is_none() {
if let Some(future) = language_server.resolve_code_action(code_action.clone()) {
if let Ok(response) = helix_lsp::block_on(future) {
if let Ok(code_action) = serde_json::from_value::<CodeAction>(response) {
resolved_code_action = Some(code_action);
}
}
pub fn resolve_code_action(
code_action: &CodeAction,
language_server: &Client,
) -> Option<CodeAction> {
// we support lsp "codeAction/resolve" for `edit` and `command` fields
let mut resolved_code_action = None;
if code_action.edit.is_none() || code_action.command.is_none() {
if let Some(future) = language_server.resolve_code_action(code_action.clone()) {
if let Ok(response) = helix_lsp::block_on(future) {
if let Ok(code_action) = serde_json::from_value::<CodeAction>(response) {
resolved_code_action = Some(code_action);
}
}
let resolved_code_action = resolved_code_action.as_ref().unwrap_or(code_action);

if let Some(ref workspace_edit) = resolved_code_action.edit {
let _ = editor.apply_workspace_edit(offset_encoding, workspace_edit);
}

// if code action provides both edit and command first the edit
// should be applied and then the command
if let Some(command) = &code_action.command {
execute_lsp_command(editor, action.language_server_id, command.clone());
}
}
}
resolved_code_action
}

pub fn execute_lsp_command(
Expand Down
10 changes: 7 additions & 3 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl Completion {
})
}
// if more text was entered, remove it
doc.restore(view, &savepoint, false);
doc.restore(view, &savepoint, None);
// always present here
let item = item.unwrap();

Expand All @@ -273,7 +273,7 @@ impl Completion {
if let Some(CompleteAction::Selected { savepoint }) =
editor.last_completion.take()
{
doc.restore(view, &savepoint, false);
doc.restore(view, &savepoint, None);
}
// always present here
let mut item = item.unwrap().clone();
Expand All @@ -289,7 +289,11 @@ impl Completion {
}
};
// if more text was entered, remove it
doc.restore(view, &savepoint, true);
doc.restore(
view,
&savepoint,
Some(helix_view::document::EmitLspNotification::Async),
);
// save an undo checkpoint before the completion
doc.append_changes_to_history(view);
let transaction = item_to_transaction(
Expand Down
8 changes: 6 additions & 2 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,11 @@ impl EditorView {
let (view, doc) = current!(cxt.editor);

if let Some(last_savepoint) = last_savepoint.as_deref() {
doc.restore(view, last_savepoint, true);
doc.restore(
view,
last_savepoint,
Some(helix_view::document::EmitLspNotification::Async),
);
}

let text = doc.text().slice(..);
Expand Down Expand Up @@ -1063,7 +1067,7 @@ impl EditorView {
}),
CompleteAction::Selected { savepoint } => {
let (view, doc) = current!(editor);
doc.restore(view, &savepoint, false);
doc.restore(view, &savepoint, None);
}
}
}
Expand Down
Loading

0 comments on commit 393de46

Please sign in to comment.