Skip to content

Commit

Permalink
feat: add multi lsp support when moving files
Browse files Browse the repository at this point in the history
  • Loading branch information
yo-main committed Oct 22, 2023
1 parent 7f47c01 commit f13e18b
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 23 deletions.
57 changes: 47 additions & 10 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,23 +705,60 @@ impl Client {
})
}

pub fn will_rename_files(
pub fn prepare_file_rename(
&self,
params: &Vec<lsp::FileRename>,
) -> impl Future<Output = Result<Option<lsp::WorkspaceEdit>>> {
let files = params.to_owned();
old_uri: &lsp::Url,
new_uri: &lsp::Url,
) -> Option<impl Future<Output = Result<lsp::WorkspaceEdit>>> {
let capabilities = self.capabilities.get().unwrap();

// Return early if the server does not support willRename feature
match &capabilities.workspace {
Some(workspace) => match &workspace.file_operations {
Some(op) => {
op.will_rename.as_ref()?;
}
_ => return None,
},
_ => return None,
}

let files = vec![lsp::FileRename {
old_uri: old_uri.to_string(),
new_uri: new_uri.to_string(),
}];
let request = self.call::<lsp::request::WillRenameFiles>(lsp::RenameFilesParams { files });

async move {
Some(async move {
let json = request.await?;
let response: Option<lsp::WorkspaceEdit> = serde_json::from_value(json)?;
Ok(response)
}
Ok(response.unwrap_or_default())
})
}

pub fn did_rename_files(&self, params: &[lsp::FileRename]) -> impl Future<Output = Result<()>> {
let files = params.to_owned();
self.notify::<lsp::notification::DidRenameFiles>(lsp::RenameFilesParams { files })
pub fn did_file_rename(
&self,
old_uri: &lsp::Url,
new_uri: &lsp::Url,
) -> Option<impl Future<Output = std::result::Result<(), Error>>> {
let capabilities = self.capabilities.get().unwrap();

// Return early if the server does not support DidRename feature
match &capabilities.workspace {
Some(workspace) => match &workspace.file_operations {
Some(op) => {
op.did_rename.as_ref()?;
}
_ => return None,
},
_ => return None,
}

let files = vec![lsp::FileRename {
old_uri: old_uri.to_string(),
new_uri: new_uri.to_string(),
}];
Some(self.notify::<lsp::notification::DidRenameFiles>(lsp::RenameFilesParams { files }))
}

// -------------------------------------------------------------------------------------------
Expand Down
66 changes: 53 additions & 13 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use std::fmt::Write;
use std::fmt::Write;
use std::ops::Deref;
use std::{ffi::OsStr, ops::Deref};

use crate::job::Job;

use super::*;

use helix_core::fuzzy::fuzzy_match;
use helix_core::{encoding, line_ending, shellwords::Shellwords};
use helix_lsp::{lsp, Url};
use helix_lsp::OffsetEncoding;
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::editor::{Action, CloseError, ConfigEvent};
use serde_json::Value;
Expand Down Expand Up @@ -2422,22 +2420,64 @@ fn move_buffer(

ensure!(args.len() == 1, format!(":move takes one argument"));

let new_path =
helix_core::path::get_normalized_path(&PathBuf::from(args.first().unwrap().as_ref()));
let (_, doc) = current!(cx.editor);
let new_path_as_url = helix_lsp::Url::from_file_path(helix_core::path::get_canonicalized_path(
&PathBuf::from(args.first().unwrap().to_string()),
))
.unwrap();

let old_path = doc
.path()
.ok_or_else(|| anyhow!("Scratch buffer cannot be moved. Use :write instead"))?
.clone();
let doc = doc!(cx.editor);
let old_path_as_url = doc
.url()
.ok_or_else(|| anyhow!("Scratch buffer cannot be moved. Use :write instead"))?;

let edits: Vec<(
helix_lsp::Result<helix_lsp::lsp::WorkspaceEdit>,
OffsetEncoding,
String,
)> = doc
.language_servers()
.map(|lsp| {
(
lsp.prepare_file_rename(&old_path_as_url, &new_path_as_url),
lsp.offset_encoding(),
lsp.name().to_owned(),
)
})
.filter(|(f, _, _)| f.is_some())
.map(|(f, encoding, name)| (helix_lsp::block_on(f.unwrap()), encoding, name))
.collect();

doc.set_path(Some(new_path.as_path()));
for (lsp_reply, encoding, name) in edits {
match lsp_reply {
Ok(edit) => {
if let Err(e) = apply_workspace_edit(cx.editor, encoding, &edit) {
log::error!(
":move command failed to apply edits from lsp {}: {:?}",
name,
e
);
};
}
Err(e) => {
log::error!("LSP {} failed to treat willRename request: {:?}", name, e);
}
};
}

if let Err(e) = std::fs::rename(&old_path, doc.path().unwrap()) {
doc.set_path(Some(old_path.as_path()));
let doc = doc_mut!(cx.editor);
doc.set_path(Some(new_path_as_url.to_file_path().unwrap().as_path()));
if let Err(e) = std::fs::rename(
&old_path_as_url.to_file_path().unwrap(),
&new_path_as_url.to_file_path().unwrap(),
) {
doc.set_path(Some(old_path_as_url.to_file_path().unwrap().as_path()));
bail!("Could not move file: {}", e);
};

doc.language_servers().for_each(|lsp| {
lsp.did_file_rename(&old_path_as_url, &new_path_as_url);
});

Ok(())
}

Expand Down

0 comments on commit f13e18b

Please sign in to comment.