From 64feeb3803aaa68d65ac6cd68916a2ba2f7858f5 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Thu, 26 Jun 2025 23:05:10 -0700 Subject: [PATCH] fix: add tiebreaker logic for paths when scores are equal (#1400) --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/1400). * #1401 * __->__ #1400 --- codex-rs/file-search/src/lib.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/codex-rs/file-search/src/lib.rs b/codex-rs/file-search/src/lib.rs index 87541816..d284d492 100644 --- a/codex-rs/file-search/src/lib.rs +++ b/codex-rs/file-search/src/lib.rs @@ -183,7 +183,7 @@ pub async fn run( } let mut matches: Vec<(u32, String)> = global_heap.into_iter().map(|r| r.0).collect(); - matches.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal)); + sort_matches(&mut matches); Ok(FileSearchResults { matches, @@ -191,6 +191,14 @@ pub async fn run( }) } +/// Sort matches in-place by descending score, then ascending path. +fn sort_matches(matches: &mut [(u32, String)]) { + matches.sort_by(|a, b| match b.0.cmp(&a.0) { + std::cmp::Ordering::Equal => a.1.cmp(&b.1), + other => other, + }); +} + /// Maintains the `max_count` best matches for a given pattern. struct BestMatchesList { max_count: usize, @@ -281,4 +289,24 @@ mod tests { let score = pattern.score(haystack, &mut matcher); assert_eq!(score, None); } + + #[test] + fn tie_breakers_sort_by_path_when_scores_equal() { + let mut matches = vec![ + (100, "b_path".to_string()), + (100, "a_path".to_string()), + (90, "zzz".to_string()), + ]; + + sort_matches(&mut matches); + + // Highest score first; ties broken alphabetically. + let expected = vec![ + (100, "a_path".to_string()), + (100, "b_path".to_string()), + (90, "zzz".to_string()), + ]; + + assert_eq!(matches, expected); + } }