11package com .devoxx .genie .service .analyzer .util ;
22
33import com .devoxx .genie .service .analyzer .tools .GlobTool ;
4- import com .intellij .openapi .vfs .VfsUtil ;
4+ import com .intellij .openapi .vfs .VfsUtilCore ;
55import com .intellij .openapi .vfs .VirtualFile ;
66import lombok .extern .slf4j .Slf4j ;
77import org .jetbrains .annotations .NotNull ;
1717 */
1818@ Slf4j
1919public class GitignoreParser {
20-
20+
2121 // Root patterns that apply to the entire project
2222 private final List <Pattern > rootExcludePatterns = new ArrayList <>();
2323 private final List <Pattern > rootIncludePatterns = new ArrayList <>();
@@ -29,6 +29,12 @@ public class GitignoreParser {
2929 // The project root directory
3030 private final VirtualFile baseDir ;
3131
32+ /**
33+ * Fast lookup map for top-level directories that are directly excluded
34+ * This avoids regex matching for common cases like "build/" and ".gradle/"
35+ */
36+ private final Set <String > directlyExcludedDirs = new HashSet <>();
37+
3238 /**
3339 * Initializes the parser by reading and parsing .gitignore files from the given directory
3440 * and its subdirectories
@@ -53,10 +59,10 @@ private void parseRootGitignore() {
5359 }
5460
5561 try {
56- String content = VfsUtil .loadText (gitignoreFile );
62+ String content = VfsUtilCore .loadText (gitignoreFile );
5763 parseGitignoreContent (content , rootExcludePatterns , rootIncludePatterns , "" );
5864 } catch (IOException e ) {
59- log .error ("Error reading root .gitignore file: " + e .getMessage ());
65+ log .error ("Error reading root .gitignore file: {}" , e .getMessage ());
6066 }
6167 }
6268
@@ -66,7 +72,7 @@ private void parseRootGitignore() {
6672 private void parseNestedGitignores () {
6773
6874 // Use a file visitor to find all nested .gitignore files
69- VfsUtil .visitChildrenRecursively (baseDir , new com .intellij .openapi .vfs .VirtualFileVisitor <Void >() {
75+ VfsUtilCore .visitChildrenRecursively (baseDir , new com .intellij .openapi .vfs .VirtualFileVisitor <Void >() {
7076 @ Override
7177 public boolean visitFile (@ NotNull VirtualFile file ) {
7278 // Skip the root .gitignore as it's already processed
@@ -81,7 +87,7 @@ public boolean visitFile(@NotNull VirtualFile file) {
8187 nestedIncludePatterns .putIfAbsent (relativeDirPath , new ArrayList <>());
8288
8389 // Parse the content
84- String content = VfsUtil .loadText (file );
90+ String content = VfsUtilCore .loadText (file );
8591 parseGitignoreContent (
8692 content ,
8793 nestedExcludePatterns .get (relativeDirPath ),
@@ -113,7 +119,6 @@ private void parseGitignoreContent(
113119 @ NotNull String relativeDir ) {
114120
115121 String [] lines = content .split ("\\ r?\\ n" );
116- String logPrefix = relativeDir .isEmpty () ? "" : "[" + relativeDir + "] " ;
117122
118123 for (String line : lines ) {
119124 // Skip empty lines and comments
@@ -124,9 +129,6 @@ private void parseGitignoreContent(
124129 // Check if it's a negation pattern (inclusion)
125130 boolean isNegation = line .startsWith ("!" );
126131 String pattern = isNegation ? line .substring (1 ).trim () : line .trim ();
127-
128- // Store the original pattern for optimization checks
129- String originalPattern = pattern ;
130132
131133 // Handle directory-only patterns that end with /
132134 boolean directoryOnly = pattern .endsWith ("/" );
@@ -171,16 +173,13 @@ private void parseGitignoreContent(
171173 */
172174 @ NotNull
173175 private String convertGitignoreToRegex (@ NotNull String pattern , boolean directoryOnly , @ NotNull String relativeDir ) {
174- // Make a copy to preserve the original pattern for logging
176+
175177 String modifiedPattern = pattern ;
176178
177179 // For nested .gitignore files, patterns are relative to that directory
178- if (!relativeDir .isEmpty ()) {
179- // If it's an absolute path (starts with /), it's relative to project root instead
180- if (!modifiedPattern .startsWith ("/" )) {
181- // For nested .gitignore files, prepend the relative directory path
182- modifiedPattern = relativeDir + "/" + modifiedPattern ;
183- }
180+ if (!relativeDir .isEmpty () && !modifiedPattern .startsWith ("/" )) {
181+ // For nested .gitignore files, prepend the relative directory path
182+ modifiedPattern = relativeDir + "/" + modifiedPattern ;
184183 }
185184
186185 // 1. Remove leading / if present - it represents the project root directory
@@ -247,12 +246,6 @@ private String getRelativePath(@NotNull VirtualFile baseDir, @NotNull VirtualFil
247246 return null ;
248247 }
249248
250- /**
251- * Fast lookup map for top-level directories that are directly excluded
252- * This avoids regex matching for common cases like "build/" and ".gradle/"
253- */
254- private final Set <String > directlyExcludedDirs = new HashSet <>();
255-
256249 /**
257250 * Checks if a file or directory should be ignored based on gitignore rules
258251 *
@@ -287,27 +280,22 @@ public boolean shouldIgnore(@NotNull String path, boolean isDirectory) {
287280 List <String > parentDirs = getParentDirectories (normalizedPath );
288281 for (String parentDir : parentDirs ) {
289282 // Don't check the path itself, just its parents
290- if (!parentDir .equals (normalizedPath )) {
291- // If the parent directory is ignored, then this path should also be ignored
292- // We use true for isDirectory since we're checking parent directories
293- if (isPathIgnored (parentDir , true )) {
294- return true ;
295- }
283+ if (!parentDir .equals (normalizedPath ) && isPathIgnored (parentDir )) {
284+ return true ;
296285 }
297286 }
298287
299288 // If no parent directory is ignored, check this path directly
300- return isPathIgnored (normalizedPath , isDirectory );
289+ return isPathIgnored (normalizedPath );
301290 }
302291
303292 /**
304293 * Internal method to check if a specific path should be ignored, without checking parent directories
305294 *
306295 * @param normalizedPath The normalized path to check
307- * @param isDirectory Whether the path represents a directory
308296 * @return true if the path should be ignored, false otherwise
309297 */
310- private boolean isPathIgnored (@ NotNull String normalizedPath , boolean isDirectory ) {
298+ private boolean isPathIgnored (@ NotNull String normalizedPath ) {
311299 // First check against root .gitignore patterns
312300
313301 // Check if the path matches any root include patterns (negations)
@@ -378,36 +366,4 @@ private List<String> getParentDirectories(@NotNull String path) {
378366 Collections .reverse (parents );
379367 return parents ;
380368 }
381-
382- /**
383- * Gets all patterns that are used to exclude files and directories at the root level
384- *
385- * @return A list of compiled regex patterns
386- */
387- @ NotNull
388- public List <Pattern > getRootExcludePatterns () {
389- return Collections .unmodifiableList (rootExcludePatterns );
390- }
391-
392- /**
393- * Gets all nested exclusion patterns for a specific directory path
394- *
395- * @param dirPath The relative directory path
396- * @return A list of compiled regex patterns, or an empty list if none exist
397- */
398- @ NotNull
399- public List <Pattern > getNestedExcludePatterns (@ NotNull String dirPath ) {
400- List <Pattern > patterns = nestedExcludePatterns .get (dirPath );
401- return patterns != null ? Collections .unmodifiableList (patterns ) : Collections .emptyList ();
402- }
403-
404- /**
405- * Gets a map of all nested exclusion patterns
406- *
407- * @return A map of directory paths to their exclusion patterns
408- */
409- @ NotNull
410- public Map <String , List <Pattern >> getAllNestedExcludePatterns () {
411- return Collections .unmodifiableMap (nestedExcludePatterns );
412- }
413369}
0 commit comments