diff options
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 24 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 24 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/main.rs | 144 |
3 files changed, 178 insertions, 14 deletions
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 3db0d55c5..f148521a2 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -75,14 +75,24 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
75 | will_create: None, | 75 | will_create: None, |
76 | did_rename: None, | 76 | did_rename: None, |
77 | will_rename: Some(FileOperationRegistrationOptions { | 77 | will_rename: Some(FileOperationRegistrationOptions { |
78 | filters: vec![FileOperationFilter { | 78 | filters: vec![ |
79 | scheme: Some(String::from("file")), | 79 | FileOperationFilter { |
80 | pattern: FileOperationPattern { | 80 | scheme: Some(String::from("file")), |
81 | glob: String::from("**/*.rs"), | 81 | pattern: FileOperationPattern { |
82 | matches: Some(FileOperationPatternKind::File), | 82 | glob: String::from("**/*.rs"), |
83 | options: None, | 83 | matches: Some(FileOperationPatternKind::File), |
84 | options: None, | ||
85 | }, | ||
84 | }, | 86 | }, |
85 | }], | 87 | FileOperationFilter { |
88 | scheme: Some(String::from("file")), | ||
89 | pattern: FileOperationPattern { | ||
90 | glob: String::from("**"), | ||
91 | matches: Some(FileOperationPatternKind::Folder), | ||
92 | options: None, | ||
93 | }, | ||
94 | }, | ||
95 | ], | ||
86 | }), | 96 | }), |
87 | did_delete: None, | 97 | did_delete: None, |
88 | will_delete: None, | 98 | will_delete: None, |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 70dd51911..dc81f55d6 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -432,9 +432,27 @@ pub(crate) fn handle_will_rename_files( | |||
432 | // Limit to single-level moves for now. | 432 | // Limit to single-level moves for now. |
433 | match (from_path.parent(), to_path.parent()) { | 433 | match (from_path.parent(), to_path.parent()) { |
434 | (Some(p1), Some(p2)) if p1 == p2 => { | 434 | (Some(p1), Some(p2)) if p1 == p2 => { |
435 | let new_name = to_path.file_stem()?; | 435 | if from_path.is_dir() { |
436 | let new_name = new_name.to_str()?; | 436 | // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/` |
437 | Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())) | 437 | let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string(); |
438 | old_folder_name.push('/'); | ||
439 | let from_with_trailing_slash = from.join(&old_folder_name).ok()?; | ||
440 | |||
441 | let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?; | ||
442 | let new_file_name = to_path.file_name()?.to_str()?; | ||
443 | Some(( | ||
444 | snap.url_to_file_id(&imitate_from_url).ok()?, | ||
445 | new_file_name.to_string(), | ||
446 | )) | ||
447 | } else { | ||
448 | let old_name = from_path.file_stem()?.to_str()?; | ||
449 | let new_name = to_path.file_stem()?.to_str()?; | ||
450 | match (old_name, new_name) { | ||
451 | ("mod", _) => None, | ||
452 | (_, "mod") => None, | ||
453 | _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())), | ||
454 | } | ||
455 | } | ||
438 | } | 456 | } |
439 | _ => None, | 457 | _ => None, |
440 | } | 458 | } |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index f5c5c63e5..80bde29b9 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs | |||
@@ -16,11 +16,14 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; | |||
16 | use expect_test::expect; | 16 | use expect_test::expect; |
17 | use lsp_types::{ | 17 | use lsp_types::{ |
18 | notification::DidOpenTextDocument, | 18 | notification::DidOpenTextDocument, |
19 | request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, | 19 | request::{ |
20 | CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, | ||
21 | WillRenameFiles, | ||
22 | }, | ||
20 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, | 23 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, |
21 | DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams, | 24 | DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams, |
22 | PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, | 25 | PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem, |
23 | WorkDoneProgressParams, | 26 | TextDocumentPositionParams, WorkDoneProgressParams, |
24 | }; | 27 | }; |
25 | use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; | 28 | use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; |
26 | use serde_json::json; | 29 | use serde_json::json; |
@@ -745,3 +748,136 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
745 | ```"#]] | 748 | ```"#]] |
746 | .assert_eq(&value); | 749 | .assert_eq(&value); |
747 | } | 750 | } |
751 | |||
752 | #[test] | ||
753 | fn test_will_rename_files_same_level() { | ||
754 | if skip_slow_tests() { | ||
755 | return; | ||
756 | } | ||
757 | |||
758 | let tmp_dir = TestDir::new(); | ||
759 | let tmp_dir_path = tmp_dir.path().to_owned(); | ||
760 | let tmp_dir_str = tmp_dir_path.to_str().unwrap(); | ||
761 | let base_path = PathBuf::from(format!("file://{}", tmp_dir_str)); | ||
762 | |||
763 | let code = r#" | ||
764 | //- /Cargo.toml | ||
765 | [package] | ||
766 | name = "foo" | ||
767 | version = "0.0.0" | ||
768 | |||
769 | //- /src/lib.rs | ||
770 | mod old_file; | ||
771 | mod from_mod; | ||
772 | mod to_mod; | ||
773 | mod old_folder; | ||
774 | fn main() {} | ||
775 | |||
776 | //- /src/old_file.rs | ||
777 | |||
778 | //- /src/old_folder/mod.rs | ||
779 | |||
780 | //- /src/from_mod/mod.rs | ||
781 | |||
782 | //- /src/to_mod/foo.rs | ||
783 | |||
784 | "#; | ||
785 | let server = | ||
786 | Project::with_fixture(&code).tmp_dir(tmp_dir).server().wait_until_workspace_is_loaded(); | ||
787 | |||
788 | //rename same level file | ||
789 | server.request::<WillRenameFiles>( | ||
790 | RenameFilesParams { | ||
791 | files: vec![FileRename { | ||
792 | old_uri: base_path.join("src/old_file.rs").to_str().unwrap().to_string(), | ||
793 | new_uri: base_path.join("src/new_file.rs").to_str().unwrap().to_string(), | ||
794 | }], | ||
795 | }, | ||
796 | json!({ | ||
797 | "documentChanges": [ | ||
798 | { | ||
799 | "textDocument": { | ||
800 | "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace("\\", "/")), | ||
801 | "version": null | ||
802 | }, | ||
803 | "edits": [ | ||
804 | { | ||
805 | "range": { | ||
806 | "start": { | ||
807 | "line": 0, | ||
808 | "character": 4 | ||
809 | }, | ||
810 | "end": { | ||
811 | "line": 0, | ||
812 | "character": 12 | ||
813 | } | ||
814 | }, | ||
815 | "newText": "new_file" | ||
816 | } | ||
817 | ] | ||
818 | } | ||
819 | ] | ||
820 | }), | ||
821 | ); | ||
822 | |||
823 | //rename file from mod.rs to foo.rs | ||
824 | server.request::<WillRenameFiles>( | ||
825 | RenameFilesParams { | ||
826 | files: vec![FileRename { | ||
827 | old_uri: base_path.join("src/from_mod/mod.rs").to_str().unwrap().to_string(), | ||
828 | new_uri: base_path.join("src/from_mod/foo.rs").to_str().unwrap().to_string(), | ||
829 | }], | ||
830 | }, | ||
831 | json!({ | ||
832 | "documentChanges": [] | ||
833 | }), | ||
834 | ); | ||
835 | |||
836 | //rename file from foo.rs to mod.rs | ||
837 | server.request::<WillRenameFiles>( | ||
838 | RenameFilesParams { | ||
839 | files: vec![FileRename { | ||
840 | old_uri: base_path.join("src/to_mod/foo.rs").to_str().unwrap().to_string(), | ||
841 | new_uri: base_path.join("src/to_mod/mod.rs").to_str().unwrap().to_string(), | ||
842 | }], | ||
843 | }, | ||
844 | json!({ | ||
845 | "documentChanges": [] | ||
846 | }), | ||
847 | ); | ||
848 | |||
849 | //rename same level file | ||
850 | server.request::<WillRenameFiles>( | ||
851 | RenameFilesParams { | ||
852 | files: vec![FileRename { | ||
853 | old_uri: base_path.join("src/old_folder").to_str().unwrap().to_string(), | ||
854 | new_uri: base_path.join("src/new_folder").to_str().unwrap().to_string(), | ||
855 | }], | ||
856 | }, | ||
857 | json!({ | ||
858 | "documentChanges": [ | ||
859 | { | ||
860 | "textDocument": { | ||
861 | "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace("\\", "/")), | ||
862 | "version": null | ||
863 | }, | ||
864 | "edits": [ | ||
865 | { | ||
866 | "range": { | ||
867 | "start": { | ||
868 | "line": 3, | ||
869 | "character": 4 | ||
870 | }, | ||
871 | "end": { | ||
872 | "line": 3, | ||
873 | "character": 14 | ||
874 | } | ||
875 | }, | ||
876 | "newText": "new_folder" | ||
877 | } | ||
878 | ] | ||
879 | } | ||
880 | ] | ||
881 | }), | ||
882 | ); | ||
883 | } | ||