From 30b54b5f02875f944457f70e85e62ac74f1bcee2 Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Wed, 8 Oct 2025 20:34:40 +0800 Subject: [PATCH 1/2] editor: Optimize selection overlap checking with binary search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace O(n²) linear search with O(log n) binary search for checking selection overlaps when finding next selection range. Pre-sort selection ranges and use binary search to significantly improve performance when working with many selections. Signed-off-by: Xiaobo Liu --- crates/editor/src/editor.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 296f6ca11de775..87fa10c7c6127b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -14383,6 +14383,13 @@ impl Editor { let last_selection = selections.iter().max_by_key(|s| s.id).unwrap(); let mut next_selected_range = None; + // Collect and sort selection ranges for efficient overlap checking + let mut selection_ranges: Vec<_> = selections + .iter() + .map(|s| s.range()) + .collect(); + selection_ranges.sort_by_key(|r| r.start); + let bytes_after_last_selection = buffer.bytes_in_range(last_selection.end..buffer.len()); let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start); @@ -14404,11 +14411,18 @@ impl Editor { || (!buffer.is_inside_word(offset_range.start, None) && !buffer.is_inside_word(offset_range.end, None)) { - // TODO: This is n^2, because we might check all the selections - if !selections - .iter() - .any(|selection| selection.range().overlaps(&offset_range)) - { + // Use binary search to check for overlap (O(log n)) + let overlaps = selection_ranges.binary_search_by(|range| { + if range.end <= offset_range.start { + std::cmp::Ordering::Less + } else if range.start >= offset_range.end { + std::cmp::Ordering::Greater + } else { + std::cmp::Ordering::Equal + } + }).is_ok(); + + if !overlaps { next_selected_range = Some(offset_range); break; } From f5e4128b245335e3661dbd66de4903f93a14c87e Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Thu, 9 Oct 2025 08:05:55 +0800 Subject: [PATCH 2/2] style Signed-off-by: Xiaobo Liu --- crates/editor/src/editor.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 87fa10c7c6127b..a6147cde7a5c8b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -14384,10 +14384,7 @@ impl Editor { let mut next_selected_range = None; // Collect and sort selection ranges for efficient overlap checking - let mut selection_ranges: Vec<_> = selections - .iter() - .map(|s| s.range()) - .collect(); + let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect(); selection_ranges.sort_by_key(|r| r.start); let bytes_after_last_selection = @@ -14412,15 +14409,17 @@ impl Editor { && !buffer.is_inside_word(offset_range.end, None)) { // Use binary search to check for overlap (O(log n)) - let overlaps = selection_ranges.binary_search_by(|range| { - if range.end <= offset_range.start { - std::cmp::Ordering::Less - } else if range.start >= offset_range.end { - std::cmp::Ordering::Greater - } else { - std::cmp::Ordering::Equal - } - }).is_ok(); + let overlaps = selection_ranges + .binary_search_by(|range| { + if range.end <= offset_range.start { + std::cmp::Ordering::Less + } else if range.start >= offset_range.end { + std::cmp::Ordering::Greater + } else { + std::cmp::Ordering::Equal + } + }) + .is_ok(); if !overlaps { next_selected_range = Some(offset_range);