Skip to content

Commit b85e96a

Browse files
JeanMertzautozimu
authored andcommitted
add client-side support for "rust-analyzer.applySourceChange"
The "rust-analyzer"[0] language server requires the clients to implement a custom source change operation. This is similar to the already existing "java.apply.workspaceEdit" functionality in this language client. This feature can be removed once rust-analyzer supports server-side file manipulation[1]. [0]: https://github.com/rust-analyzer/rust-analyzer [1]: rust-lang/rust-analyzer#1232
1 parent 3b6274f commit b85e96a

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

src/language_server_protocol.rs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -804,20 +804,61 @@ impl LanguageClient {
804804
Ok(text.trim().into())
805805
}
806806

807+
fn edit_and_move(
808+
&self,
809+
(edit, cursor): (WorkspaceEdit, Option<TextDocumentPositionParams>),
810+
) -> Fallible<()> {
811+
self.apply_WorkspaceEdit(&edit)?;
812+
813+
if let Some(cursor) = cursor {
814+
self.vim()?
815+
.cursor(cursor.position.line + 1, cursor.position.character + 1)?;
816+
}
817+
818+
Ok(())
819+
}
820+
807821
fn try_handle_command_by_client(&self, cmd: &Command) -> Fallible<bool> {
822+
use serde_json::{from_value, Map};
823+
808824
if !CommandsClient.contains(&cmd.command.as_str()) {
809825
return Ok(false);
810826
}
811827

812-
if cmd.command == "java.apply.workspaceEdit" {
813-
if let Some(ref edits) = cmd.arguments {
814-
for edit in edits {
815-
let edit: WorkspaceEdit = serde_json::from_value(edit.clone())?;
816-
self.apply_WorkspaceEdit(&edit)?;
828+
match cmd.command.as_str() {
829+
"java.apply.workspaceEdit" => {
830+
if let Some(ref edits) = cmd.arguments {
831+
for edit in edits {
832+
let edit: WorkspaceEdit = from_value(edit.clone())?;
833+
self.apply_WorkspaceEdit(&edit)?;
834+
}
817835
}
818836
}
819-
} else {
820-
bail!("Not implemented: {}", cmd.command);
837+
"rust-analyzer.applySourceChange" => {
838+
fn json_to_workspace_edit(
839+
json: Value,
840+
) -> Fallible<(WorkspaceEdit, Option<TextDocumentPositionParams>)> {
841+
let mut map: Map<String, Value> = from_value(json)?;
842+
let ws = from_value::<WorkspaceEdit>(
843+
map.remove("workspaceEdit").unwrap_or_default(),
844+
);
845+
let cursor = from_value::<TextDocumentPositionParams>(
846+
map.remove("cursorPosition").unwrap_or_default(),
847+
)
848+
.ok();
849+
850+
ws.map(|ws| (ws, cursor))
851+
.map_err(|err| format_err!("invalid workspaceEdit: {}", err))
852+
};
853+
854+
cmd.arguments
855+
.iter()
856+
.flat_map(Clone::clone)
857+
.map(json_to_workspace_edit)
858+
.try_for_each(|tuple| self.edit_and_move(tuple?))?
859+
}
860+
861+
cmd => bail!("Not implemented: {}", cmd),
821862
}
822863

823864
Ok(true)

src/types.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ pub const NOTIFICATION__WindowProgress: &str = "window/progress";
5555
pub const NOTIFICATION__LanguageStatus: &str = "language/status";
5656
pub const REQUEST__ClassFileContents: &str = "java/classFileContents";
5757

58-
pub const CommandsClient: &[&str] = &["java.apply.workspaceEdit"];
58+
pub const CommandsClient: &[&str] = &[
59+
"java.apply.workspaceEdit",
60+
"rust-analyzer.applySourceChange",
61+
];
5962

6063
// Vim variable names
6164
pub const VIM__ServerStatus: &str = "g:LanguageClient_serverStatus";

0 commit comments

Comments
 (0)