22import { EventEmitter } from "events"
33import minimatch from "minimatch"
44import { Directory , File } from "atom"
5+ import { dirname , basename } from "path"
56import { union } from "./utils"
67import { globifyPath , globifyDirectory , globifyGitIgnoreFile } from "globify-gitignore"
78import glob from "fast-glob"
@@ -18,10 +19,11 @@ export default class PathsCache extends EventEmitter {
1819 this . _projectWatcher = atom . project . onDidChangeFiles ( _onDidChangeFilesBound )
1920
2021 this . _repositories = [ ]
22+ // TODO remove _filePathsByProjectDirectory and only use _filePathsByDirectory
2123 this . _filePathsByProjectDirectory = new Map ( )
2224 this . _filePathsByDirectory = new Map ( )
2325 this . _fileWatchersByDirectory = new Map ( )
24-
26+ this . _allIgnoredGlob = [ ]
2527 this . updateConfig ( )
2628 }
2729
@@ -173,15 +175,23 @@ export default class PathsCache extends EventEmitter {
173175 }
174176 // add a watcher to run `this._onDirectoryChanged`
175177 const projectPath = projectDirectory . getPath ( )
176- const ignored = await this . _getAllIgnoredGlob ( projectPath )
178+ const ignored = this . _allIgnoredGlob
177179 // TODO smarter handling of directory changes
178180 // TODO get paths from the watcher itself
179181 // TODO track gitignore file
180182 watcher = chokidar
181183 . watch ( [ projectPath , ...ignored ] , {
182184 persistent : true ,
185+ ignoreInitial : true , // do not run the listeners on the initial scan
183186 } )
184187 . on ( "add" , ( addedFile ) => {
188+ // we should track it too!
189+ // if (basename(addedFile) === ".gitignore") {
190+ // // if a gitignore file is added re-process the folder
191+ // this.onRemoveDir(projectDirectory, removedDir)
192+ // this.onAddDir(projectDirectory, removedDir)
193+ // return
194+ // }
185195 this . onAddFile ( projectDirectory , addedFile )
186196 } )
187197 . on ( "unlink" , ( removedFile ) => {
@@ -201,53 +211,40 @@ export default class PathsCache extends EventEmitter {
201211 * @param addedFile {string}
202212 */
203213 onAddFile ( projectDirectory , addedFile ) {
204- this . emit ( "rebuild-cache" )
205214 const filePaths = this . _filePathsByProjectDirectory . get ( projectDirectory . path )
206215 filePaths . push ( addedFile )
207216 this . _filePathsByProjectDirectory . set ( projectDirectory . path , filePaths )
208- this . emit ( "rebuild-cache-done" )
209217 }
210218
211219 /**
212220 * @param projectDirectory {Directory}
213221 * @param removedFile {string}
214222 */
215223 onRemoveFile ( projectDirectory , removedFile ) {
216- this . emit ( "rebuild-cache" )
217224 /** @type {string[] } */
218225 const filePaths = this . _filePathsByProjectDirectory . get ( projectDirectory . path )
219226
220227 // delete the removed file
221- for ( let iFile = 0 ; iFile < filePaths . length ; iFile ++ ) {
222- const file = filePaths [ iFile ]
223- if ( file === removedFile ) {
224- delete filePaths [ iFile ]
225- }
226- }
228+ const fileIndex = filePaths . indexOf ( removedFile )
229+ delete filePaths [ fileIndex ]
227230 this . _filePathsByProjectDirectory . set ( projectDirectory . path , filePaths )
228- this . emit ( "rebuild-cache-done" )
229231 }
230232
231233 /**
232234 * @param projectDirectory {Directory}
233235 * @param addedDir {string}
234236 */
235237 async onAddDir ( projectDirectory , addedDir ) {
236- this . emit ( "rebuild-cache" )
237- const directory = new Directory ( addedDir )
238- await this . _cachePathsForDirectory ( projectDirectory , directory )
239- this . emit ( "rebuild-cache-done" )
238+ await this . _cachePathsForDirectoryWithGlob ( addedDir )
240239 }
241240
242241 /**
243242 * @param projectDirectory {Directory}
244243 * @param removedDir {string}
245244 */
246245 onRemoveDir ( projectDirectory , removedDir ) {
247- this . emit ( "rebuild-cache" )
248246 const directory = new Directory ( removedDir )
249247 this . _removeFilePathsForDirectory ( projectDirectory , directory )
250- this . emit ( "rebuild-cache-done" )
251248 }
252249
253250 /**
@@ -442,18 +439,28 @@ export default class PathsCache extends EventEmitter {
442439 }
443440
444441 /**
445- * Returns the glob pattern of a gitignore of a directory
446- * @param {string } directoryPath
442+ * Returns the glob pattern of all gitignore files in a directory
443+ * @param {string } rootDirectory
444+ * @param {string[] } ignoredPatternsGlob
447445 * @returns {Promise<Array<string>> } an array of glob patterns
448446 * @private
449447 */
450- async _getGitIgnoreGlob ( directoryPath ) {
448+ async _getAllGitIgnoreGlob ( rootDirectory , ignoredPatternsGlob ) {
451449 if ( this . config . excludeVcsIgnoredPaths ) {
452- try {
453- return await globifyGitIgnoreFile ( directoryPath )
454- } catch ( err ) {
455- // .gitignore does not exist for this directory, ignoring
456- }
450+ // get gitignore files
451+ const gitignoreFiles = await glob (
452+ [ "**/.gitignore" , ...ignoredPatternsGlob ] ,
453+ // glob options
454+ {
455+ dot : true ,
456+ cwd : rootDirectory ,
457+ onlyFiles : true ,
458+ absolute : true ,
459+ }
460+ )
461+ return (
462+ await Promise . all ( gitignoreFiles . map ( ( gitignoreFile ) => _getDirectoryGitIgnoreGlob ( dirname ( gitignoreFile ) ) ) )
463+ ) . flat ( )
457464 }
458465 return [ ]
459466 }
@@ -464,8 +471,8 @@ export default class PathsCache extends EventEmitter {
464471 * @returns {Promise<string[]> }
465472 */
466473 async _getAllIgnoredGlob ( directoryPath ) {
467- const gitignoreGlob = await this . _getGitIgnoreGlob ( directoryPath )
468474 const ignoredPatternsGlob = await this . _getIgnoredPatternsGlob ( directoryPath )
475+ const gitignoreGlob = await this . _getAllGitIgnoreGlob ( directoryPath , ignoredPatternsGlob )
469476 return [ ...gitignoreGlob , ...ignoredPatternsGlob ]
470477 }
471478
@@ -477,8 +484,9 @@ export default class PathsCache extends EventEmitter {
477484 */
478485 async _cachePathsForDirectoryWithGlob ( directoryPath ) {
479486 const directoryGlob = globifyDirectory ( directoryPath )
487+ this . _allIgnoredGlob = await this . _getAllIgnoredGlob ( directoryPath )
480488 const files = await glob (
481- [ directoryGlob , ...( await this . _getAllIgnoredGlob ( directoryPath ) ) ] ,
489+ [ directoryGlob , ...this . _allIgnoredGlob ] ,
482490 // glob options
483491 {
484492 dot : true ,
@@ -566,3 +574,18 @@ export default class PathsCache extends EventEmitter {
566574 return Promise . all ( directories . map ( ( dir ) => this . _cachePathsForDirectoryWithAtom ( projectDirectory , dir ) ) )
567575 }
568576}
577+
578+ /**
579+ * Returns the glob pattern of a gitignore of a directory
580+ * @param {string } directoryPath
581+ * @returns {Promise<Array<string>> } an array of glob patterns
582+ * @private
583+ */
584+ function _getDirectoryGitIgnoreGlob ( directoryPath ) {
585+ try {
586+ return globifyGitIgnoreFile ( directoryPath )
587+ } catch ( err ) {
588+ // .gitignore does not exist for this directory, ignoring
589+ return [ ]
590+ }
591+ }
0 commit comments