From 31034f8296e47a03de8bfd5bbab1d246b312db2c Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Wed, 9 Apr 2025 08:44:53 -0400 Subject: [PATCH] Add toggle case command (#28415) A small addition for those coming from JetBrain's IDEs. A behavioral detail: when any upper case character is detected, the command defaults to toggling to lower case. > Note that when you apply the toggle case action to the CamelCase name format, IntelliJ IDEA converts the name to the lower case. https://www.jetbrains.com/help/idea/working-with-source-code.html#edit_code_fragments Release Notes: - Added an `editor: toggle case` command. Use `cmd-shift-u` for macOS and `ctrl-shift-u` for Linux, when using the `JetBrains` keymap. --- assets/keymaps/linux/jetbrains.json | 3 ++- assets/keymaps/macos/jetbrains.json | 3 ++- crates/editor/src/actions.rs | 1 + crates/editor/src/editor.rs | 11 +++++++++ crates/editor/src/editor_tests.rs | 35 +++++++++++++++++++++++++++++ crates/editor/src/element.rs | 1 + 6 files changed, 52 insertions(+), 2 deletions(-) diff --git a/assets/keymaps/linux/jetbrains.json b/assets/keymaps/linux/jetbrains.json index 43937701cf13a63d54dc39baa7c087adc3ac7764..dbf50b0fcefa99063f0c8f535bd453aade4d7e56 100644 --- a/assets/keymaps/linux/jetbrains.json +++ b/assets/keymaps/linux/jetbrains.json @@ -58,7 +58,8 @@ "ctrl-shift-home": "editor::SelectToBeginning", "ctrl-shift-end": "editor::SelectToEnd", "ctrl-f8": "editor::ToggleBreakpoint", - "ctrl-shift-f8": "editor::EditLogBreakpoint" + "ctrl-shift-f8": "editor::EditLogBreakpoint", + "ctrl-shift-u": "editor::ToggleCase" } }, { diff --git a/assets/keymaps/macos/jetbrains.json b/assets/keymaps/macos/jetbrains.json index 355e86090813b70d5dbe3ae460b637cf6cedd973..22c6f18383a32f5def1869b953e31baf665404b9 100644 --- a/assets/keymaps/macos/jetbrains.json +++ b/assets/keymaps/macos/jetbrains.json @@ -55,7 +55,8 @@ "cmd-shift-home": "editor::SelectToBeginning", "cmd-shift-end": "editor::SelectToEnd", "ctrl-f8": "editor::ToggleBreakpoint", - "ctrl-shift-f8": "editor::EditLogBreakpoint" + "ctrl-shift-f8": "editor::EditLogBreakpoint", + "cmd-shift-u": "editor::ToggleCase" } }, { diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 3ac782599360ca3929dd58242895564739ea8d06..670d21478f492f49b2de74bd1369d99565035a43 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -420,6 +420,7 @@ actions!( Tab, Backtab, ToggleBreakpoint, + ToggleCase, DisableBreakpoint, EnableBreakpoint, EditLogBreakpoint, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 5539cea460ff25b7edb3551ab5979526741593f4..6290a0606a27dd7e9e78fd877c7c4fbbfab738b7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -9143,6 +9143,17 @@ impl Editor { }); } + pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context) { + self.manipulate_text(window, cx, |text| { + let has_upper_case_characters = text.chars().any(|c| c.is_uppercase()); + if has_upper_case_characters { + text.to_lowercase() + } else { + text.to_uppercase() + } + }) + } + pub fn convert_to_upper_case( &mut self, _: &ConvertToUpperCase, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 915edc237fb84ef3a26743d370e1c54391dd1f2a..761add2715d62a7ca747df0cbbef700783c420bb 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -3875,6 +3875,41 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { "}); } +#[gpui::test] +async fn test_toggle_case(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + + // If all lower case -> upper case + cx.set_state(indoc! {" + «hello worldˇ» + "}); + cx.update_editor(|e, window, cx| e.toggle_case(&ToggleCase, window, cx)); + cx.assert_editor_state(indoc! {" + «HELLO WORLDˇ» + "}); + + // If all upper case -> lower case + cx.set_state(indoc! {" + «HELLO WORLDˇ» + "}); + cx.update_editor(|e, window, cx| e.toggle_case(&ToggleCase, window, cx)); + cx.assert_editor_state(indoc! {" + «hello worldˇ» + "}); + + // If any upper case characters are identified -> lower case + // This matches JetBrains IDEs + cx.set_state(indoc! {" + «hEllo worldˇ» + "}); + cx.update_editor(|e, window, cx| e.toggle_case(&ToggleCase, window, cx)); + cx.assert_editor_state(indoc! {" + «hello worldˇ» + "}); +} + #[gpui::test] async fn test_manipulate_text(cx: &mut TestAppContext) { init_test(cx, |_| {}); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index e9719b6a1fa0cf4501fd9d7387ce83c42601e536..54c65f05e6d720d0be64170c58668cb31a71929d 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -211,6 +211,7 @@ impl EditorElement { register_action(editor, window, Editor::sort_lines_case_insensitive); register_action(editor, window, Editor::reverse_lines); register_action(editor, window, Editor::shuffle_lines); + register_action(editor, window, Editor::toggle_case); register_action(editor, window, Editor::convert_to_upper_case); register_action(editor, window, Editor::convert_to_lower_case); register_action(editor, window, Editor::convert_to_title_case);