@@ -9,18 +9,25 @@ import { Tool } from "./types.js";
99
1010const execPromise = util . promisify ( child_process . exec ) ;
1111
12- async function getGitignorePatterns ( ) {
12+ async function getGitignorePatterns ( ) : Promise < {
13+ ignorePatterns : string [ ] ;
14+ negatedPatterns : string [ ] ;
15+ } > {
1316 const gitIgnorePath = await findUp ( ".gitignore" ) ;
14- if ( ! gitIgnorePath ) return [ ] ;
17+ if ( ! gitIgnorePath ) return { ignorePatterns : [ ] , negatedPatterns : [ ] } ;
1518 const content = fs . readFileSync ( gitIgnorePath , "utf-8" ) ;
16- const ignorePatterns = [ ] ;
19+ const ignorePatterns : string [ ] = [ ] ;
20+ const negatedPatterns : string [ ] = [ ] ;
1721 for ( let line of content . trim ( ) . split ( "\n" ) ) {
1822 line = line . trim ( ) ;
19- if ( line . startsWith ( "#" ) || line === "" ) continue ; // ignore comments and empty line
20- if ( line . startsWith ( "!" ) ) continue ; // ignore negated ignores
21- ignorePatterns . push ( line ) ;
23+ if ( line . startsWith ( "#" ) || line === "" ) continue ;
24+ if ( line . startsWith ( "!" ) ) {
25+ negatedPatterns . push ( line . slice ( 1 ) ) ;
26+ } else {
27+ ignorePatterns . push ( line ) ;
28+ }
2229 }
23- return ignorePatterns ;
30+ return { ignorePatterns, negatedPatterns } ;
2431}
2532
2633// procedure 1: search with ripgrep
@@ -44,10 +51,13 @@ async function searchWithRipgrep(
4451 command += ` -g "${ filePattern } "` ;
4552 }
4653
47- const ignorePatterns = await getGitignorePatterns ( ) ;
54+ const { ignorePatterns, negatedPatterns } = await getGitignorePatterns ( ) ;
4855 for ( const ignorePattern of ignorePatterns ) {
4956 command += ` -g "!${ ignorePattern } "` ;
5057 }
58+ for ( const negatedPattern of negatedPatterns ) {
59+ command += ` -g "${ negatedPattern } "` ;
60+ }
5161
5262 command += ` "${ searchPath } "` ;
5363 const { stdout, stderr } = await execPromise ( command ) ;
@@ -61,20 +71,24 @@ async function searchWithGrepOrFindstr(
6171 filePattern ?: string ,
6272) {
6373 const isWindows = process . platform === "win32" ;
64- const ignorePatterns = await getGitignorePatterns ( ) ;
74+ const { ignorePatterns, negatedPatterns } = await getGitignorePatterns ( ) ;
6575 let command : string ;
6676 if ( isWindows ) {
6777 const fileSpec = filePattern ? filePattern : "*" ;
6878 command = `findstr /S /N /P /R "${ pattern } " "${ fileSpec } "` ; // findstr does not support ignoring patterns
6979 } else {
7080 let excludeArgs = "" ;
7181 for ( const ignorePattern of ignorePatterns ) {
72- excludeArgs += ` --exclude="${ ignorePattern } " --exclude-dir="${ ignorePattern } "` ; // use both exclude and exclude-dir because ignorePattern can be a file or directory
82+ excludeArgs += ` --exclude="${ ignorePattern } " --exclude-dir="${ ignorePattern } "` ;
83+ }
84+ let includeArgs = "" ;
85+ for ( const negatedPattern of negatedPatterns ) {
86+ includeArgs += ` --include="${ negatedPattern } "` ;
7387 }
7488 if ( filePattern ) {
75- command = `find . -type f -path " ${ filePattern } " -print0 | xargs -0 grep -nH -I ${ excludeArgs } "${ pattern } "` ;
89+ command = `grep -R -n -H -I ${ excludeArgs } ${ includeArgs } --include=" ${ filePattern } " "${ pattern } " . ` ;
7690 } else {
77- command = `grep -R -n -H -I${ excludeArgs } "${ pattern } " .` ;
91+ command = `grep -R -n -H -I${ excludeArgs } ${ includeArgs } "${ pattern } " .` ;
7892 }
7993 }
8094 return await execPromise ( command , { cwd : searchPath } ) ;
0 commit comments