Skip to content

Commit 8a715c3

Browse files
authored
feat(excludes): improved noting of excluded files (#50)
1 parent e457316 commit 8a715c3

File tree

4 files changed

+158
-17
lines changed

4 files changed

+158
-17
lines changed

filesystem/defaultExcludes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const defaultGlobContent = `
111111
**/*.terraform.tfstate.lock.info
112112
**/.terraform/*
113113
**/.webpack/*
114+
**/vendor/*
114115
115116
# Specific files
116117
**/.editorconfig

filesystem/filesystem.go

Lines changed: 128 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,19 @@ type FileInfo struct {
2626
Code string `json:"code"`
2727
}
2828

29+
// New type to track excluded files and directories
30+
type ExcludedInfo struct {
31+
Directories map[string]int // Directory path -> count of excluded files
32+
Extensions map[string]int // File extension -> count of excluded files
33+
TotalFiles int // Total number of excluded files
34+
Files []string // List of excluded files (if total ≤ 20)
35+
}
36+
2937
type treeNode struct {
3038
name string
3139
children []*treeNode
3240
isDir bool
41+
excluded bool
3342
}
3443

3544
func ReadExcludePatterns(patternExclude string, noDefaultExcludes bool) ([]string, error) {
@@ -58,9 +67,9 @@ func ReadExcludePatterns(patternExclude string, noDefaultExcludes bool) ([]strin
5867
// If user has a default.glob, it overrides the default patterns
5968
if _, err := os.Stat(userDefaultGlob); err == nil {
6069
return readGlobFile(userDefaultGlob)
61-
}
70+
}
6271

63-
// Read other user-defined patterns
72+
// Read other user-defined patterns
6473
userPatterns, _ := readGlobFilesFromDir(userPatternsDir)
6574

6675
// Combine user patterns with default patterns (if not disabled)
@@ -70,6 +79,30 @@ func ReadExcludePatterns(patternExclude string, noDefaultExcludes bool) ([]strin
7079
return patterns, nil
7180
}
7281

82+
// Helper functions to track exclusions
83+
func trackExcludedFile(excluded *ExcludedInfo, path string, mu *sync.Mutex) {
84+
mu.Lock()
85+
defer mu.Unlock()
86+
87+
excluded.TotalFiles++
88+
89+
// Track the directory
90+
dir := filepath.Dir(path)
91+
excluded.Directories[dir]++
92+
93+
// Track the extension
94+
ext := filepath.Ext(path)
95+
if ext != "" {
96+
excluded.Extensions[ext]++
97+
}
98+
99+
// Only store individual files if we haven't exceeded 20
100+
if excluded.TotalFiles <= 20 {
101+
excluded.Files = append(excluded.Files, path)
102+
}
103+
}
104+
105+
73106
func readGlobFile(filename string) ([]string, error) {
74107
file, err := os.Open(filename)
75108
if err != nil {
@@ -111,15 +144,27 @@ func readGlobFilesFromDir(dir string) ([]string, error) {
111144
return patterns, err
112145
}
113146

114-
func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, patternExclude string, includePriority, lineNumber, relativePaths, excludeFromTree, noCodeblock, noDefaultExcludes bool) (string, []FileInfo, error) {
147+
func trackExcludedDirectory(excluded *ExcludedInfo, path string, mu *sync.Mutex) {
148+
mu.Lock()
149+
defer mu.Unlock()
150+
excluded.Directories[path] = 0 // Initialize directory count
151+
}
152+
153+
func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, patternExclude string, includePriority, lineNumber, relativePaths, excludeFromTree, noCodeblock, noDefaultExcludes bool) (string, []FileInfo, *ExcludedInfo, error) {
115154
var files []FileInfo
116155
var mu sync.Mutex
117156
var wg sync.WaitGroup
118157

158+
excluded := &ExcludedInfo{
159+
Directories: make(map[string]int),
160+
Extensions: make(map[string]int),
161+
Files: make([]string, 0),
162+
}
163+
119164
// Read exclude patterns
120165
defaultExcludes, err := ReadExcludePatterns(patternExclude, noDefaultExcludes)
121166
if err != nil {
122-
return "", nil, fmt.Errorf("failed to read exclude patterns: %w", err)
167+
return "", nil, nil, fmt.Errorf("failed to read exclude patterns: %w", err)
123168
}
124169

125170
// Combine user-provided exclude patterns with default excludes (if not disabled)
@@ -131,34 +176,34 @@ func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, p
131176
// Read .gitignore if it exists
132177
gitignore, err := readGitignore(rootPath)
133178
if err != nil {
134-
return "", nil, fmt.Errorf("failed to read .gitignore: %w", err)
179+
return "", nil, nil, fmt.Errorf("failed to read .gitignore: %w", err)
135180
}
136181

137182
// Check if rootPath is a file or directory
138183
fileInfo, err := os.Stat(rootPath)
139184
if err != nil {
140-
return "", nil, fmt.Errorf("failed to get file info: %w", err)
185+
return "", nil, nil, fmt.Errorf("failed to get file info: %w", err)
141186
}
142187

143188
// Check if rootPath is a single PDF file
144189
if !fileInfo.IsDir() {
145190
isPDF, err := pdf.IsPDF(rootPath)
146191
if err != nil {
147-
return "", nil, fmt.Errorf("failed to check if file is PDF: %w", err)
192+
return "", nil, nil, fmt.Errorf("failed to check if file is PDF: %w", err)
148193
}
149194

150195
if isPDF {
151196
// Process single PDF file directly
152197
content, err := pdf.ConvertPDFToMarkdown(rootPath, false)
153198
if err != nil {
154-
return "", nil, fmt.Errorf("failed to convert PDF: %w", err)
199+
return "", nil, nil, fmt.Errorf("failed to convert PDF: %w", err)
155200
}
156201

157202
return fmt.Sprintf("File: %s", rootPath), []FileInfo{{
158203
Path: rootPath,
159204
Extension: ".md",
160205
Code: content,
161-
}}, nil
206+
}}, excluded, nil
162207
}
163208
}
164209

@@ -173,13 +218,15 @@ func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, p
173218
defer wg.Done()
174219
processFile(rootPath, relPath, filepath.Dir(rootPath), lineNumber, relativePaths, noCodeblock, &mu, &files)
175220
}()
221+
} else {
222+
trackExcludedFile(excluded, rootPath, &mu)
176223
}
177224
treeString = fmt.Sprintf("File: %s", rootPath)
178225
} else {
179226
// Generate the tree representation for directory
180227
treeString, err = generateTreeString(rootPath, allExcludePatterns)
181228
if err != nil {
182-
return "", nil, fmt.Errorf("failed to generate directory tree: %w", err)
229+
return "", nil, nil, fmt.Errorf("failed to generate directory tree: %w", err)
183230
}
184231

185232
// Process files in directory
@@ -196,8 +243,15 @@ func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, p
196243
// Check if the current path (file or directory) should be excluded
197244
if shouldExcludePath(relPath, allExcludePatterns, gitignore) {
198245
if info.IsDir() {
246+
trackExcludedDirectory(excluded, path, &mu)
199247
return filepath.SkipDir
200248
}
249+
trackExcludedFile(excluded, path, &mu)
250+
return nil
251+
}
252+
253+
if !info.IsDir() && !shouldIncludeFile(relPath, includePatterns, allExcludePatterns, gitignore, includePriority) {
254+
trackExcludedFile(excluded, path, &mu)
201255
return nil
202256
}
203257

@@ -216,18 +270,18 @@ func WalkDirectory(rootPath string, includePatterns, excludePatterns []string, p
216270
wg.Wait()
217271

218272
if err != nil {
219-
return "", nil, err
273+
return "", nil, excluded, err
220274
}
221275

222-
return treeString, files, nil
276+
return treeString, files, excluded, nil
223277
}
224278

225279
// New helper function to check if a path should be excluded
226280
func shouldExcludePath(path string, excludePatterns []string, gitignore *ignore.GitIgnore) bool {
227281
for _, pattern := range excludePatterns {
228282
if match, _ := doublestar.Match(pattern, path); match {
229283
return true
230-
}
284+
}
231285
}
232286
return gitignore != nil && gitignore.MatchesPath(path)
233287
}
@@ -299,7 +353,7 @@ func isBinaryFile(filePath string) (bool, error) {
299353
n, err := file.Read(buffer)
300354
if err != nil && err != io.EOF {
301355
return false, err
302-
}
356+
}
303357

304358
// Use http.DetectContentType to determine the content type
305359
contentType := http.DetectContentType(buffer[:n])
@@ -397,6 +451,8 @@ func processFile(path, relPath string, rootPath string, lineNumber, relativePath
397451

398452
func generateTreeString(rootPath string, excludePatterns []string) (string, error) {
399453
root := &treeNode{name: filepath.Base(rootPath), isDir: true}
454+
hasExclusions := false
455+
400456
err := filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error {
401457
if err != nil {
402458
return err
@@ -413,10 +469,60 @@ func generateTreeString(rootPath string, excludePatterns []string) (string, erro
413469
}
414470

415471
// Check if the path should be excluded
416-
if isExcluded(relPath, excludePatterns) {
472+
excluded := isExcluded(relPath, excludePatterns)
473+
if excluded {
474+
hasExclusions = true
417475
if info.IsDir() {
476+
// Add the excluded directory to the tree with an X marker
477+
parts := strings.Split(relPath, string(os.PathSeparator))
478+
current := root
479+
for i, part := range parts {
480+
found := false
481+
for _, child := range current.children {
482+
if child.name == part {
483+
current = child
484+
found = true
485+
break
486+
}
487+
}
488+
if !found {
489+
newNode := &treeNode{
490+
name: part,
491+
isDir: true,
492+
excluded: true,
493+
}
494+
current.children = append(current.children, newNode)
495+
current = newNode
496+
}
497+
if i == len(parts)-1 {
498+
current.isDir = true
499+
current.excluded = true
500+
}
501+
}
418502
return filepath.SkipDir
419503
}
504+
// Add excluded files to the tree with an X marker
505+
parts := strings.Split(relPath, string(os.PathSeparator))
506+
current := root
507+
for i, part := range parts {
508+
found := false
509+
for _, child := range current.children {
510+
if child.name == part {
511+
current = child
512+
found = true
513+
break
514+
}
515+
}
516+
if !found {
517+
newNode := &treeNode{
518+
name: part,
519+
isDir: i < len(parts)-1,
520+
excluded: true,
521+
}
522+
current.children = append(current.children, newNode)
523+
current = newNode
524+
}
525+
}
420526
return nil
421527
}
422528

@@ -449,6 +555,9 @@ func generateTreeString(rootPath string, excludePatterns []string) (string, erro
449555
}
450556

451557
var output strings.Builder
558+
if hasExclusions {
559+
output.WriteString("(Files/directories marked with ❌ are excluded or not included here)\n\n")
560+
}
452561
output.WriteString(root.name + "/\n")
453562
for i, child := range root.children {
454563
printTree(child, "", i == len(root.children)-1, &output)
@@ -470,6 +579,9 @@ func printTree(node *treeNode, prefix string, isLast bool, output *strings.Build
470579
if node.isDir {
471580
output.WriteString("/")
472581
}
582+
if node.excluded {
583+
output.WriteString(" ❌")
584+
}
473585
output.WriteString("\n")
474586

475587
sort.Slice(node.children, func(i, j int) bool {
@@ -483,6 +595,7 @@ func printTree(node *treeNode, prefix string, isLast bool, output *strings.Build
483595
printTree(child, prefix, i == len(node.children)-1, output)
484596
}
485597
}
598+
486599
func isExcluded(path string, patterns []string) bool {
487600
for _, pattern := range patterns {
488601
if match, _ := doublestar.Match(pattern, path); match {

main.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ func run(cmd *cobra.Command, args []string) error {
236236
var allFiles []filesystem.FileInfo
237237
var allTrees []string
238238
var gitData []GitData
239+
var allExcluded []*filesystem.ExcludedInfo
239240

240241
remainingArgs := make([]string, len(args))
241242
copy(remainingArgs, args)
@@ -275,10 +276,11 @@ func run(cmd *cobra.Command, args []string) error {
275276

276277
var files []filesystem.FileInfo
277278
var tree string
279+
var excluded *filesystem.ExcludedInfo
278280

279281
if fileInfo.IsDir() {
280282
// Existing directory processing logic
281-
tree, files, err = filesystem.WalkDirectory(absPath, includePatterns, excludePatterns, patternExclude, includePriority, lineNumber, relativePaths, excludeFromTree, noCodeblock, noDefaultExcludes)
283+
tree, files, excluded, err = filesystem.WalkDirectory(absPath, includePatterns, excludePatterns, patternExclude, includePriority, lineNumber, relativePaths, excludeFromTree, noCodeblock, noDefaultExcludes)
282284
if err != nil {
283285
return fmt.Errorf("failed to process directory %s: %w", arg, err)
284286
}
@@ -295,6 +297,9 @@ func run(cmd *cobra.Command, args []string) error {
295297

296298
allFiles = append(allFiles, files...)
297299
allTrees = append(allTrees, tree)
300+
if excluded != nil {
301+
allExcluded = append(allExcluded, excluded)
302+
}
298303

299304
// Handle git operations for each path
300305
gitDiffContent := ""
@@ -342,8 +347,10 @@ func run(cmd *cobra.Command, args []string) error {
342347
"source_trees": strings.Join(allTrees, "\n\n"),
343348
"files": allFiles,
344349
"git_data": gitData,
350+
"excluded": allExcluded[0], // Use the first excluded info if there are multiple paths
345351
}
346352

353+
347354
if err := spinner.Finish(); err != nil {
348355
return fmt.Errorf("failed to finish spinner: %w", err)
349356
}

template/template.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,33 @@ func getDefaultTemplate() (string, error) {
5757
return readEmbeddedTemplate()
5858
}
5959

60-
6160
func readEmbeddedTemplate() (string, error) {
6261
return `
6362
Source Trees:
6463
6564
{{.source_trees}}
6665
66+
{{if .excluded}}
67+
Excluded Content:
68+
{{if le .excluded.TotalFiles 20}}
69+
Files:
70+
{{range .excluded.Files}}
71+
- {{.}}
72+
{{end}}
73+
{{else}}
74+
Directories with excluded files:
75+
{{range $dir, $count := .excluded.Directories}}
76+
{{if gt $count 0}}- {{$dir}}: {{$count}} files{{end}}
77+
{{end}}
78+
79+
File extensions excluded:
80+
{{range $ext, $count := .excluded.Extensions}}
81+
- {{$ext}}: {{$count}} files
82+
{{end}}
83+
{{end}}
84+
85+
{{end}}
86+
6787
{{range .files}}
6888
{{if .Code}}
6989
` + "`{{.Path}}:`" + `

0 commit comments

Comments
 (0)