@@ -21,6 +21,7 @@ import type {
2121 SearchResult ,
2222 MixedItem ,
2323} from "@ff-labs/fff-node" ;
24+ import { buildQuery } from "./query" ;
2425
2526// ---------------------------------------------------------------------------
2627// Constants
@@ -104,65 +105,6 @@ function getFindCursor(id: string): FindCursor | undefined {
104105 return findCursorCache . get ( id ) ;
105106}
106107
107- // ---------------------------------------------------------------------------
108- // Query building helpers
109- // ---------------------------------------------------------------------------
110-
111- function normalizePathConstraint ( path : string ) : string | null {
112- let trimmed = path . trim ( ) ;
113- if ( ! trimmed ) return trimmed ;
114- if ( trimmed === "." || trimmed === "./" ) return null ;
115- // Strip a leading `./` so `./**/*.rs` and `**/*.rs` behave identically.
116- if ( trimmed . startsWith ( "./" ) ) trimmed = trimmed . slice ( 2 ) ;
117- // Already signals path-constraint syntax to the parser.
118- if ( trimmed . startsWith ( "/" ) || trimmed . endsWith ( "/" ) ) return trimmed ;
119- // Globs (`*.ts`, `src/**/*.cc`, `{src,lib}`) are handled by the parser.
120- if ( / [ * ? \[ { ] / . test ( trimmed ) ) return trimmed ;
121- // Filename with extension (`main.rs`, `config.json`) → FilePath constraint.
122- const lastSegment = trimmed . split ( "/" ) . pop ( ) ?? "" ;
123- if ( / \. [ a - z A - Z ] [ a - z A - Z 0 - 9 ] { 0 , 9 } $ / . test ( lastSegment ) ) return trimmed ;
124- // Bare directory prefix → append `/` so the parser sees a PathSegment.
125- return `${ trimmed } /` ;
126- }
127-
128- // Exclusions are emitted as `!<constraint>` tokens, which the Rust parser
129- // understands (crates/fff-query-parser/src/parser.rs). We normalize each one
130- // the same way as the include path so bare dirs become PathSegment excludes.
131- // Tolerate callers passing already-negated forms like `!src/` by stripping
132- // the leading `!` before normalizing so we never double-negate (`!!src/`).
133- function normalizeExcludes ( exclude : string | string [ ] | undefined ) : string [ ] {
134- if ( ! exclude ) return [ ] ;
135- const list = Array . isArray ( exclude ) ? exclude : [ exclude ] ;
136- const out : string [ ] = [ ] ;
137- for ( const raw of list ) {
138- const parts = raw
139- . split ( / [ , \s ] + / )
140- . map ( ( s ) => s . trim ( ) )
141- . filter ( Boolean ) ;
142- for ( const p of parts ) {
143- const stripped = p . startsWith ( "!" ) ? p . slice ( 1 ) : p ;
144- const normalized = normalizePathConstraint ( stripped ) ;
145- if ( normalized ) out . push ( `!${ normalized } ` ) ;
146- }
147- }
148- return out ;
149- }
150-
151- function buildQuery (
152- path : string | undefined ,
153- pattern : string ,
154- exclude ?: string | string [ ] ,
155- ) : string {
156- const parts : string [ ] = [ ] ;
157- if ( path ) {
158- const pathConstraint = normalizePathConstraint ( path ) ;
159- if ( pathConstraint ) parts . push ( pathConstraint ) ;
160- }
161- parts . push ( ...normalizeExcludes ( exclude ) ) ;
162- parts . push ( pattern ) ;
163- return parts . join ( " " ) ;
164- }
165-
166108// ---------------------------------------------------------------------------
167109// Output formatting helpers
168110// ---------------------------------------------------------------------------
@@ -650,7 +592,7 @@ export default function fffExtension(pi: ExtensionAPI) {
650592
651593 const f = await ensureFinder ( activeCwd ) ;
652594 const effectiveLimit = Math . max ( 1 , params . limit ?? DEFAULT_GREP_LIMIT ) ;
653- const query = buildQuery ( params . path , params . pattern , params . exclude ) ;
595+ const query = buildQuery ( params . path , params . pattern , params . exclude , activeCwd ) ;
654596 // Auto-detect: regex if the pattern has regex metacharacters AND parses
655597 // as a valid regex, otherwise plain literal. The fuzzy fallback below
656598 // only kicks in for plain mode — regex queries are intentional.
@@ -829,7 +771,7 @@ export default function fffExtension(pi: ExtensionAPI) {
829771 : Math . max ( 1 , params . limit ?? DEFAULT_FIND_LIMIT ) ;
830772 const query = resumed
831773 ? resumed . query
832- : buildQuery ( params . path , params . pattern , params . exclude ) ;
774+ : buildQuery ( params . path , params . pattern , params . exclude , activeCwd ) ;
833775 const pattern = resumed ? resumed . pattern : params . pattern ;
834776 const pageIndex = resumed ?. nextPageIndex ?? 0 ;
835777
0 commit comments