From 3f3227150f2e17f12052ffcf5765617e671e572b Mon Sep 17 00:00:00 2001 From: jcarver989 <117696+jcarver989@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:19:33 +0000 Subject: [PATCH] chore: scheduled code-cleanup --- .../src/coding/tools/ast_grep/mod.rs | 4 +- .../mcp-servers/src/coding/tools/find/mod.rs | 5 +- .../src/coding/tools/glob_filter.rs | 46 ++++++++++++++----- .../mcp-servers/src/coding/tools/grep/mod.rs | 4 +- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/crates/mcp-servers/src/coding/tools/ast_grep/mod.rs b/crates/mcp-servers/src/coding/tools/ast_grep/mod.rs index 246fb91c6..2ecdc1690 100644 --- a/crates/mcp-servers/src/coding/tools/ast_grep/mod.rs +++ b/crates/mcp-servers/src/coding/tools/ast_grep/mod.rs @@ -1,5 +1,5 @@ use crate::coding::error::AstGrepError; -use crate::coding::tools::glob_filter::{PathGlobMatcher, build_path_matcher}; +use crate::coding::tools::glob_filter::{CaseSensitivity, PathGlobMatcher, build_path_matcher}; use ast_grep_core::Doc; use ast_grep_core::matcher::{NodeMatch, Pattern}; use ast_grep_language::{Language, LanguageExt, SupportLang}; @@ -99,7 +99,7 @@ pub async fn perform_ast_grep(mut args: AstGrepInput) -> Result Result { return Err(FindError::PathNotFound(search_path.to_string())); } - let path_matcher = Arc::new(PathGlobMatcher::new(&args.pattern, args.case_insensitive.unwrap_or(false))?); + let path_matcher = + Arc::new(PathGlobMatcher::new(&args.pattern, CaseSensitivity::from_optional(args.case_insensitive))?); let state = Arc::new(FindState::new(args.limit)); let mut walker_builder = WalkBuilder::new(search_root); diff --git a/crates/mcp-servers/src/coding/tools/glob_filter.rs b/crates/mcp-servers/src/coding/tools/glob_filter.rs index 4bb83a95f..1d171b92f 100644 --- a/crates/mcp-servers/src/coding/tools/glob_filter.rs +++ b/crates/mcp-servers/src/coding/tools/glob_filter.rs @@ -2,6 +2,27 @@ use crate::coding::error::GlobError; use globset::{GlobBuilder, GlobSet, GlobSetBuilder}; use std::path::Path; +/// Whether glob matching distinguishes uppercase from lowercase. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CaseSensitivity { + /// Match patterns exactly, respecting case. + Sensitive, + /// Match patterns ignoring case differences. + Insensitive, +} + +impl CaseSensitivity { + /// Map a nullable "case-insensitive" flag (e.g. from a tool input) onto a + /// concrete sensitivity, treating `None`/`Some(false)` as case-sensitive. + pub fn from_optional(case_insensitive: Option) -> Self { + if case_insensitive.unwrap_or(false) { Self::Insensitive } else { Self::Sensitive } + } + + fn is_insensitive(self) -> bool { + matches!(self, Self::Insensitive) + } +} + #[derive(Debug, Clone)] pub struct PathGlobMatcher { matcher: GlobSet, @@ -14,12 +35,15 @@ enum PathGlobKind { RelativePath, } -pub fn build_path_matcher(glob: Option<&str>, case_insensitive: bool) -> Result, GlobError> { - glob.map(|glob| PathGlobMatcher::new(glob, case_insensitive)).transpose() +pub fn build_path_matcher( + glob: Option<&str>, + case_sensitivity: CaseSensitivity, +) -> Result, GlobError> { + glob.map(|glob| PathGlobMatcher::new(glob, case_sensitivity)).transpose() } impl PathGlobMatcher { - pub fn new(pattern: &str, case_insensitive: bool) -> Result { + pub fn new(pattern: &str, case_sensitivity: CaseSensitivity) -> Result { if pattern.is_empty() { return Err(GlobError::InvalidPattern { pattern: pattern.to_string(), @@ -29,7 +53,7 @@ impl PathGlobMatcher { let kind = if contains_separator(pattern) { PathGlobKind::RelativePath } else { PathGlobKind::Basename }; let mut builder = GlobSetBuilder::new(); - add_glob(&mut builder, pattern, case_insensitive)?; + add_glob(&mut builder, pattern, case_sensitivity)?; // globset's `**/` requires at least one leading directory, so `**/*.rs` // on its own misses files at the search root. Also register the @@ -37,7 +61,7 @@ impl PathGlobMatcher { if let Some(root_pattern) = pattern.strip_prefix("**/") && !root_pattern.is_empty() { - add_glob(&mut builder, root_pattern, case_insensitive)?; + add_glob(&mut builder, root_pattern, case_sensitivity)?; } Ok(Self { matcher: builder.build().map_err(|e| GlobError::BuildFailed(e.to_string()))?, kind }) @@ -53,9 +77,9 @@ impl PathGlobMatcher { } } -fn add_glob(builder: &mut GlobSetBuilder, pattern: &str, case_insensitive: bool) -> Result<(), GlobError> { +fn add_glob(builder: &mut GlobSetBuilder, pattern: &str, case_sensitivity: CaseSensitivity) -> Result<(), GlobError> { let glob = GlobBuilder::new(pattern) - .case_insensitive(case_insensitive) + .case_insensitive(case_sensitivity.is_insensitive()) .build() .map_err(|e| GlobError::InvalidPattern { pattern: pattern.to_string(), reason: e.to_string() })?; builder.add(glob); @@ -72,7 +96,7 @@ mod tests { #[test] fn bare_patterns_match_basenames_at_any_depth() { - let matcher = PathGlobMatcher::new("README*", false).unwrap(); + let matcher = PathGlobMatcher::new("README*", CaseSensitivity::Sensitive).unwrap(); let root = Path::new("/workspace"); assert!(matcher.matches(Path::new("/workspace/README.md"), root)); @@ -82,7 +106,7 @@ mod tests { #[test] fn slash_patterns_match_relative_paths_only() { - let matcher = PathGlobMatcher::new("crates/**/*.rs", false).unwrap(); + let matcher = PathGlobMatcher::new("crates/**/*.rs", CaseSensitivity::Sensitive).unwrap(); let root = Path::new("/workspace"); assert!(matcher.matches(Path::new("/workspace/crates/app/src/lib.rs"), root)); @@ -92,7 +116,7 @@ mod tests { #[test] fn recursive_slash_patterns_match_root_files() { - let matcher = PathGlobMatcher::new("**/*.rs", false).unwrap(); + let matcher = PathGlobMatcher::new("**/*.rs", CaseSensitivity::Sensitive).unwrap(); let root = Path::new("/workspace"); assert!(matcher.matches(Path::new("/workspace/lib.rs"), root)); @@ -101,7 +125,7 @@ mod tests { #[test] fn case_insensitive_patterns_match_basenames() { - let matcher = PathGlobMatcher::new("readme*", true).unwrap(); + let matcher = PathGlobMatcher::new("readme*", CaseSensitivity::Insensitive).unwrap(); assert!(matcher.matches(Path::new("/workspace/README.md"), Path::new("/workspace"))); } } diff --git a/crates/mcp-servers/src/coding/tools/grep/mod.rs b/crates/mcp-servers/src/coding/tools/grep/mod.rs index e2974a314..18a45bb7a 100644 --- a/crates/mcp-servers/src/coding/tools/grep/mod.rs +++ b/crates/mcp-servers/src/coding/tools/grep/mod.rs @@ -1,7 +1,7 @@ pub mod common; use crate::coding::error::GrepError; -use crate::coding::tools::glob_filter::{PathGlobMatcher, build_path_matcher}; +use crate::coding::tools::glob_filter::{CaseSensitivity, PathGlobMatcher, build_path_matcher}; use aether_lspd::extensions_for_alias as extensions_for_type; use common::{CountSink, HasMatchSink, MatchCollectorSink, MatchData, OutputMode}; use grep::{ @@ -156,7 +156,7 @@ fn perform_grep_sync(mut args: GrepInput) -> Result { args.path = None; } - let path_matcher = build_path_matcher(args.glob.as_deref(), false)?; + let path_matcher = build_path_matcher(args.glob.as_deref(), CaseSensitivity::Sensitive)?; let matcher = build_matcher(&args.pattern, args.case_insensitive, args.multiline)?;