editor: Treat blank rename as no-op (#62630)
Confirming an inline rename after deleting the entire symbol name or entering only whitespace currently submits an invalid rename request to the language server. This can remove the symbol text instead of leaving the source unchanged. Treat empty and whitespace-only replacements as successful no-ops after dismissing the inline rename UI. Returning a completed task also consumes the confirmation action, preventing Enter from propagating back into the editor. Non-blank rename behavior remains unchanged. The regression test covers both empty and whitespace-only rename fields, verifying that no LSP rename request is sent and the original buffer remains intact. Release Notes: - editor: Fixed confirming a blank symbol LSP-rename modifying the source code
This commit is contained in:
1 parent
f7356481e7
commit
a5234566b4
2 files changed
+87
-1
No files matched your search
@@ -8026,6 +8026,11 @@ impl Editor {
|
||||
return None;
|
||||
}
|
||||
let rename = self.take_rename(false, window, cx)?;
|
||||
let new_name = rename.editor.read(cx).text(cx);
|
||||
if new_name.trim().is_empty() {
|
||||
return Some(Task::ready(Ok(())));
|
||||
}
|
||||
|
||||
let workspace = self.workspace()?.downgrade();
|
||||
let (buffer, start) = self
|
||||
.buffer
|
||||
@@ -8040,7 +8045,6 @@ impl Editor {
|
||||
}
|
||||
|
||||
let old_name = rename.old_name;
|
||||
let new_name = rename.editor.read(cx).text(cx);
|
||||
|
||||
let rename = self.semantics_provider.as_ref()?.perform_rename(
|
||||
&buffer,
|
||||
|
||||
@@ -33205,6 +33205,88 @@ async fn test_go_to_bookmark_with_out_of_order_bookmarks(cx: &mut TestAppContext
|
||||
assert_eq!(ctx.cursor_row(), 1, "Prev from row 5 should go to row 1");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_empty_rename_is_no_op(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
|
||||
prepare_provider: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
let mut cx = EditorLspTestContext::new_rust(capabilities, cx).await;
|
||||
|
||||
cx.set_state("let aˇbc = 1;");
|
||||
|
||||
let rename_request_count = Arc::new(AtomicUsize::new(0));
|
||||
let _rename_handler = cx.set_request_handler::<lsp::request::Rename, _, _>({
|
||||
let rename_request_count = rename_request_count.clone();
|
||||
move |_, _, _| {
|
||||
rename_request_count.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
async { Ok(None) }
|
||||
}
|
||||
});
|
||||
let mut prepare_rename_handler = cx
|
||||
.set_request_handler::<lsp::request::PrepareRenameRequest, _, _>(
|
||||
move |_, _, _| async move {
|
||||
Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 0,
|
||||
character: 4,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 0,
|
||||
character: 7,
|
||||
},
|
||||
})))
|
||||
},
|
||||
);
|
||||
|
||||
for new_name in ["", " "] {
|
||||
let prepare_rename_task = cx
|
||||
.update_editor(|editor, window, cx| editor.rename(&Rename, window, cx))
|
||||
.expect("Prepare rename was not started");
|
||||
prepare_rename_handler.next().await.unwrap();
|
||||
prepare_rename_task.await.expect("Prepare rename failed");
|
||||
|
||||
let rename_editor = cx.editor(|editor, _, _| {
|
||||
editor
|
||||
.pending_rename()
|
||||
.expect("Rename should still be pending")
|
||||
.editor
|
||||
.clone()
|
||||
});
|
||||
rename_editor.update_in(&mut cx.cx.cx, |editor, window, cx| {
|
||||
editor.backspace(&Backspace, window, cx);
|
||||
editor.insert(new_name, window, cx);
|
||||
});
|
||||
assert_eq!(
|
||||
cx.editor(|editor, _, cx| {
|
||||
editor
|
||||
.pending_rename()
|
||||
.expect("Rename should still be pending")
|
||||
.editor
|
||||
.read(cx)
|
||||
.text(cx)
|
||||
}),
|
||||
new_name
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor
|
||||
.confirm_rename(&ConfirmRename, window, cx)
|
||||
.expect("Confirm rename should consume the action")
|
||||
})
|
||||
.await
|
||||
.expect("Confirm rename failed");
|
||||
|
||||
assert_eq!(rename_request_count.load(atomic::Ordering::SeqCst), 0);
|
||||
assert!(cx.editor(|editor, _, _| editor.pending_rename().is_none()));
|
||||
assert_eq!(cx.buffer_text(), "let abc = 1;");
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_rename_with_duplicate_edits(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
Reference in new issue
Block a user