diff options
Diffstat (limited to 'helix-term/src/commands/typed.rs')
-rw-r--r-- | helix-term/src/commands/typed.rs | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index e7343308..4148257f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -6,7 +6,8 @@ use crate::job::Job; use super::*; use helix_core::fuzzy::fuzzy_match; -use helix_core::{encoding, line_ending, shellwords::Shellwords}; +use helix_core::{encoding, line_ending, path::get_canonicalized_path, shellwords::Shellwords}; +use helix_lsp::{OffsetEncoding, Url}; use helix_view::document::DEFAULT_LANGUAGE_NAME; use helix_view::editor::{Action, CloseError, ConfigEvent}; use serde_json::Value; @@ -2408,6 +2409,80 @@ fn redraw( Ok(()) } +fn move_buffer( + cx: &mut compositor::Context, + args: &[Cow<str>], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + ensure!(args.len() == 1, format!(":move takes one argument")); + let doc = doc!(cx.editor); + + let new_path = get_canonicalized_path(&PathBuf::from(args.first().unwrap().to_string())); + let old_path = doc + .path() + .ok_or_else(|| anyhow!("Scratch buffer cannot be moved. Use :write instead"))? + .clone(); + let old_path_as_url = doc.url().unwrap(); + let new_path_as_url = Url::from_file_path(&new_path).unwrap(); + + 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(); + + 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); + } + }; + } + + let doc = doc_mut!(cx.editor); + + doc.set_path(Some(new_path.as_path())); + if let Err(e) = std::fs::rename(&old_path, &new_path) { + doc.set_path(Some(old_path.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); + }); + + cx.editor + .language_servers + .file_event_handler + .file_changed(new_path); + + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -3008,6 +3083,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: redraw, signature: CommandSignature::none(), }, + TypableCommand { + name: "move", + aliases: &[], + doc: "Move the current buffer and its corresponding file to a different path", + fun: move_buffer, + signature: CommandSignature::positional(&[completers::filename]), + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> = |