feat: move file name derivation into codex-file-search (#8334)

## Summary

  - centralize file name derivation in codex-file-search
  - reuse the helper in app-server fuzzy search to avoid duplicate logic
  - add unit tests for file_name_from_path

  ## Testing

  - cargo test -p codex-file-search
  - cargo test -p codex-app-server
This commit is contained in:
RQfreefly
2025-12-20 04:50:55 +08:00
committed by GitHub
parent 1d4463ba81
commit ec3738b47e
4 changed files with 24 additions and 6 deletions

1
codex-rs/Cargo.lock generated
View File

@@ -1454,6 +1454,7 @@ dependencies = [
"clap",
"ignore",
"nucleo-matcher",
"pretty_assertions",
"serde",
"serde_json",
"tokio",

View File

@@ -1,6 +1,5 @@
use std::num::NonZero;
use std::num::NonZeroUsize;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
@@ -63,11 +62,7 @@ pub(crate) async fn run_fuzzy_file_search(
Ok(Ok((root, res))) => {
for m in res.matches {
let path = m.path;
//TODO(shijie): Move file name generation to file_search lib.
let file_name = Path::new(&path)
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.clone());
let file_name = file_search::file_name_from_path(&path);
let result = FuzzyFileSearchResult {
root: root.clone(),
path,

View File

@@ -20,3 +20,6 @@ nucleo-matcher = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
[dev-dependencies]
pretty_assertions = { workspace = true }

View File

@@ -40,6 +40,14 @@ pub struct FileMatch {
pub indices: Option<Vec<u32>>, // Sorted & deduplicated when present
}
/// Returns the final path component for a matched path, falling back to the full path.
pub fn file_name_from_path(path: &str) -> String {
Path::new(path)
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.to_string())
}
#[derive(Debug)]
pub struct FileSearchResults {
pub matches: Vec<FileMatch>,
@@ -403,6 +411,7 @@ fn create_pattern(pattern: &str) -> Pattern {
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn verify_score_is_none_for_non_match() {
@@ -434,4 +443,14 @@ mod tests {
assert_eq!(matches, expected);
}
#[test]
fn file_name_from_path_uses_basename() {
assert_eq!(file_name_from_path("foo/bar.txt"), "bar.txt");
}
#[test]
fn file_name_from_path_falls_back_to_full_path() {
assert_eq!(file_name_from_path(""), "");
}
}