From 8cc3b094d23afaa5cad9326831e2cc461a586296 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Mon, 7 Jul 2025 19:02:35 +0200 Subject: [PATCH] editor: Add action to sort lines by length (#33622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change introduces a new `Action` implementation to sort lines by their `char` length. It reuses the same calculation as used for getting the caret column position, i.e. `TextSummary`. The motivation is to e.g. handle source code where this sort of order matters ([example](https://github.com/alexpovel/srgn/blob/fdf537c3d3e4c18ebf3426bb34759400552a82c3/tests/readme.rs#L529-L535)). Tested manually via `cargo build && ./target/debug/zed .`: the new action shows up in the command palette, and testing it on `.mailmap` entries turns those from ```text Agus Zubiaga Agus Zubiaga Alex Viscreanu Alex Viscreanu Alexander Mankuta Alexander Mankuta amtoaer amtoaer Andrei Zvonimir Crnković Andrei Zvonimir Crnković Angelk90 Angelk90 <20476002+Angelk90@users.noreply.github.com> Antonio Scandurra Antonio Scandurra Ben Kunkle Ben Kunkle Bennet Bo Fenner Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com> Bennet Bo Fenner Boris Cherny Boris Cherny Brian Tan Chris Hayes Christian Bergschneider Christian Bergschneider Conrad Irwin Conrad Irwin Dairon Medina Danilo Leal Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Edwin Aronsson <75266237+4teapo@users.noreply.github.com> Elvis Pranskevichus Elvis Pranskevichus Evren Sen Evren Sen <146845123+evrensen467@users.noreply.github.com> Evren Sen <146845123+evrsen@users.noreply.github.com> Fernando Tagawa Fernando Tagawa Finn Evers Finn Evers <75036051+MrSubidubi@users.noreply.github.com> Finn Evers Gowtham K <73059450+dovakin0007@users.noreply.github.com> Greg Morenz Greg Morenz Ihnat Aŭtuška Ivan Žužak Ivan Žužak Joseph T. Lyons Joseph T. Lyons Julia Julia <30666851+ForLoveOfCats@users.noreply.github.com> Kaylee Simmons Kaylee Simmons Kaylee Simmons Kaylee Simmons Kirill Bulatov Kirill Bulatov Kyle Caverly Kyle Caverly Lilith Iris Lilith Iris <83819417+Irilith@users.noreply.github.com> LoganDark LoganDark LoganDark Marko Kungla Marko Kungla Marshall Bowers Marshall Bowers Marshall Bowers Matt Fellenz Matt Fellenz Max Brunsfeld Max Brunsfeld Max Linke Max Linke Michael Sloan Michael Sloan Michael Sloan Mikayla Maki Mikayla Maki Mikayla Maki Morgan Krey Muhammad Talal Anwar Muhammad Talal Anwar Nate Butler Nate Butler Nathan Sobo Nathan Sobo Nathan Sobo Nigel Jose Nigel Jose Peter Tripp Peter Tripp Petros Amoiridis Petros Amoiridis Piotr Osiewicz Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Pocæus Pocæus Rashid Almheiri Rashid Almheiri <69181766+huwaireb@users.noreply.github.com> Richard Feldman Richard Feldman Robert Clover Robert Clover Roy Williams Roy Williams Sebastijan Kelnerič Sebastijan Kelnerič Sergey Onufrienko Shish Shish Smit Barmase <0xtimsb@gmail.com> Smit Barmase <0xtimsb@gmail.com> Thomas Thomas Thomas Thomas Heartman Thomas Heartman Thomas Mickley-Doyle Thomas Mickley-Doyle Thorben Kröger Thorben Kröger Thorsten Ball Thorsten Ball Thorsten Ball Tristan Hume Tristan Hume Uladzislau Kaminski Uladzislau Kaminski Vitaly Slobodin Vitaly Slobodin Will Bradley Will Bradley WindSoilder 张小白 <364772080@qq.com> ```` into ```text 张小白 <364772080@qq.com> Ben Kunkle Finn Evers Agus Zubiaga amtoaer Peter Tripp Pocæus Danilo Leal Matt Fellenz Morgan Krey Nathan Sobo Robert Clover Conrad Irwin Ivan Žužak Mikayla Maki Piotr Osiewicz Shish Evren Sen Kirill Bulatov Michael Sloan Angelk90 Max Linke Smit Barmase <0xtimsb@gmail.com> Thorben Kröger Antonio Scandurra Bennet Bo Fenner Brian Tan Julia Nigel Jose Petros Amoiridis Rashid Almheiri Thomas Boris Cherny Nate Butler Thorsten Ball Tristan Hume Richard Feldman Greg Morenz Kaylee Simmons Lilith Iris Marshall Bowers Muhammad Talal Anwar Kyle Caverly Marko Kungla WindSoilder Alexander Mankuta Chris Hayes Max Brunsfeld Dairon Medina Elvis Pranskevichus Agus Zubiaga Alex Viscreanu Ihnat Aŭtuška Joseph T. Lyons Uladzislau Kaminski Will Bradley LoganDark Roy Williams Sergey Onufrienko Andrei Zvonimir Crnković Fernando Tagawa Vitaly Slobodin Nathan Sobo Thomas Mickley-Doyle Ben Kunkle Smit Barmase <0xtimsb@gmail.com> Finn Evers Robert Clover amtoaer Nate Butler Thomas Heartman Kaylee Simmons Peter Tripp Petros Amoiridis Pocæus Antonio Scandurra Bennet Bo Fenner Matt Fellenz Michael Sloan Nathan Sobo Sebastijan Kelnerič Shish Kaylee Simmons Kyle Caverly Max Brunsfeld Michael Sloan Ivan Žužak Richard Feldman Thorsten Ball Conrad Irwin Kirill Bulatov Marshall Bowers Will Bradley Christian Bergschneider Elvis Pranskevichus Greg Morenz Thorsten Ball Edwin Aronsson <75266237+4teapo@users.noreply.github.com> Gowtham K <73059450+dovakin0007@users.noreply.github.com> Marko Kungla Mikayla Maki Mikayla Maki Tristan Hume Thomas Boris Cherny Kaylee Simmons Thomas Muhammad Talal Anwar Roy Williams Marshall Bowers Thorben Kröger Andrei Zvonimir Crnković Thomas Mickley-Doyle Alexander Mankuta LoganDark Max Linke Alex Viscreanu Finn Evers <75036051+MrSubidubi@users.noreply.github.com> Nigel Jose Uladzislau Kaminski LoganDark Thomas Heartman Christian Bergschneider Evren Sen <146845123+evrsen@users.noreply.github.com> Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Vitaly Slobodin Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Angelk90 <20476002+Angelk90@users.noreply.github.com> Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com> Rashid Almheiri <69181766+huwaireb@users.noreply.github.com> Evren Sen <146845123+evrensen467@users.noreply.github.com> Joseph T. Lyons Lilith Iris <83819417+Irilith@users.noreply.github.com> Fernando Tagawa Julia <30666851+ForLoveOfCats@users.noreply.github.com> Sebastijan Kelnerič ``` which looks good. There's a bit of Unicode in there -- though no grapheme clusters. Column number calculations do not seem to handle grapheme clusters either (?) so I thought this is OK. Open questions are: - should this be added to vim mode as well? - is `TextSummary` the way to go here? Is it perhaps too expensive? (it seems fine -- manually counting `char`s seems more brittle -- this way it will stay in sync with column number calculations) --- Team, I realize you [ask for a discussion to be opened first](https://github.com/zed-industries/zed/blob/86161aa427b9e8b18486272ca436c344224e8ba4/CONTRIBUTING.md#L32), so apologies for not doing that! It turned out hacking on Zed was much easier than expected (it's really nice!), and this change is small, adding a variation to an existing feature. Hope that's fine. Release Notes: - Added feature to sort lines by their length --------- Co-authored-by: Conrad Irwin --- crates/editor/src/actions.rs | 2 ++ crates/editor/src/editor.rs | 11 +++++++++++ crates/editor/src/editor_tests.rs | 23 +++++++++++++++++++++++ crates/editor/src/element.rs | 1 + 4 files changed, 37 insertions(+) diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index def2a616a8..70ec8ea00f 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -635,6 +635,8 @@ actions!( SignatureHelpNext, /// Navigates to the previous signature in the signature help popup. SignatureHelpPrevious, + /// Sorts selected lines by length. + SortLinesByLength, /// Sorts selected lines case-insensitively. SortLinesCaseInsensitive, /// Sorts selected lines case-sensitively. diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 47223aa59a..6d529287a7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -10204,6 +10204,17 @@ impl Editor { self.manipulate_immutable_lines(window, cx, |lines| lines.sort()) } + pub fn sort_lines_by_length( + &mut self, + _: &SortLinesByLength, + window: &mut Window, + cx: &mut Context, + ) { + self.manipulate_immutable_lines(window, cx, |lines| { + lines.sort_by_key(|&line| line.chars().count()) + }) + } + pub fn sort_lines_case_insensitive( &mut self, _: &SortLinesCaseInsensitive, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index ade9a9322b..05280de02b 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4075,6 +4075,29 @@ async fn test_manipulate_immutable_lines_with_single_selection(cx: &mut TestAppC Zˇ» "}); + // Test sort_lines_by_length() + // + // Demonstrates: + // - ∞ is 3 bytes UTF-8, but sorted by its char count (1) + // - sort is stable + cx.set_state(indoc! {" + «123 + æ + 12 + ∞ + 1 + æˇ» + "}); + cx.update_editor(|e, window, cx| e.sort_lines_by_length(&SortLinesByLength, window, cx)); + cx.assert_editor_state(indoc! {" + «æ + ∞ + 1 + æ + 12 + 123ˇ» + "}); + // Test reverse_lines() cx.set_state(indoc! {" «5 diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 3fa8697c19..49f4fc52ac 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -225,6 +225,7 @@ impl EditorElement { register_action(editor, window, Editor::autoindent); register_action(editor, window, Editor::delete_line); register_action(editor, window, Editor::join_lines); + register_action(editor, window, Editor::sort_lines_by_length); register_action(editor, window, Editor::sort_lines_case_sensitive); register_action(editor, window, Editor::sort_lines_case_insensitive); register_action(editor, window, Editor::reverse_lines);