Compare commits

..

2 Commits

Author SHA1 Message Date
Zayden-Jung 5e5727f021 fix obscure bugs 2026-05-16 03:56:06 +08:00
Zayden-Jung 3012507fcc a version with known bug fixed but not sure any more obscure ones 2026-05-16 03:55:00 +08:00
4 changed files with 173 additions and 59 deletions
+7 -5
View File
@@ -6,11 +6,13 @@ prompts:
preset: preset:
all: all:
- "cmd/*" - "*"
- "internal/tree/*" # - "cmd/*"
- "internal/utils/*" # - "internal/tree/*"
- "internal/config/*" # - "internal/utils/*"
- "main.go" # - "internal/config/*"
# - "internal/resolver/*"
# - "main.go"
internal: internal:
- "internal/tree/*" - "internal/tree/*"
+27 -15
View File
@@ -4,14 +4,15 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"cliprepo/internal/config" "cliprepo/internal/config"
"cliprepo/internal/resolver"
"cliprepo/internal/tree" "cliprepo/internal/tree"
"cliprepo/internal/utils"
"github.com/spf13/cobra"
"github.com/atotto/clipboard" "github.com/atotto/clipboard"
"github.com/spf13/cobra"
) )
var delineate string var delineate string
@@ -35,43 +36,53 @@ var runCmd = &cobra.Command{
} }
var builder strings.Builder var builder strings.Builder
// builder.WriteString("===== PROJECT TREE =====\n")
builder.WriteString(treeStr) builder.WriteString(treeStr)
builder.WriteString("\n\n") builder.WriteString("\n\n")
// 2. preset files // 2. resolver (GLOBAL FILE REGISTRY)
var patterns []string r := resolver.New(".")
raw, ok := cfg.Preset[delineate] raw, ok := cfg.Preset[delineate]
if !ok { if !ok {
return fmt.Errorf("preset not found: %s", delineate) return fmt.Errorf("preset not found: %s", delineate)
} }
patterns = append(patterns, raw...) patterns := []string(raw)
var files []string
files, err := utils.ExpandGlob(patterns) for _, pattern := range patterns {
if err != nil { // 统一交给 resolver 处理,无论是 "*", "cmd/*" 还是 "**/*.go"
return err matches, err := r.ResolvePattern(pattern)
if err != nil {
return err
}
files = append(files, matches...)
} }
// 3. template // 3. dedup + stable order
files = r.Unique(files)
sort.Strings(files)
// 4. template
template := cfg.Prompts.Preset template := cfg.Prompts.Preset
if template == "" {
template = "The following code is from file {{path}}:\n---\n{{content}}"
}
// 5. render
for _, file := range files { for _, file := range files {
content, err := os.ReadFile(file) content, err := os.ReadFile(file)
if err != nil { if err != nil {
continue continue
} }
path := file filePath := file
if cfg.Config.PathMode == "absolute" { if cfg.Config.PathMode == "absolute" {
abs, _ := filepath.Abs(file) abs, _ := filepath.Abs(file)
path = abs filePath = abs
} }
block := strings.ReplaceAll(template, "{{path}}", path) block := strings.ReplaceAll(template, "{{path}}", filePath)
block = strings.ReplaceAll(block, "{{content}}", string(content)) block = strings.ReplaceAll(block, "{{content}}", string(content))
builder.WriteString(block) builder.WriteString(block)
@@ -80,6 +91,7 @@ var runCmd = &cobra.Command{
result := builder.String() result := builder.String()
// 6. output
if useClipboard { if useClipboard {
return clipboard.WriteAll(result) return clipboard.WriteAll(result)
} }
+132
View File
@@ -0,0 +1,132 @@
package resolver
import (
"cliprepo/internal/tree"
"os"
"path/filepath"
)
type Resolver struct {
root string
seen map[string]struct{}
}
func New(root string) *Resolver {
return &Resolver{
root: root,
seen: make(map[string]struct{}),
}
}
// ResolvePattern 智能解析各种 pattern 并过滤 ignore 文件
func (r *Resolver) ResolvePattern(pattern string) ([]string, error) {
if pattern == "*" {
return r.WalkAll()
}
var matches []string
// 处理类似 cmd/* 或 internal/tree/* 的情况
// 如果包含 * 且不是以 ** 开头,转换为通过 filepath.Walk 匹配或直接 Glob 过滤
rawMatches, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
ig, _ := tree.Load(r.root)
for _, m := range rawMatches {
info, err := os.Stat(m)
if err != nil {
continue
}
rel, _ := filepath.Rel(r.root, m)
// 统一检查 .gitignore
if ig != nil && ig.MatchesPath(rel) {
continue
}
if info.IsDir() {
// 如果匹配到的是目录(比如 internal/* 匹配到了 internal/config),则深层遍历该目录
err := filepath.Walk(m, func(path string, fInfo os.FileInfo, walkErr error) error {
if walkErr != nil || fInfo.IsDir() {
return nil
}
fRel, _ := filepath.Rel(r.root, path)
if ig != nil && ig.MatchesPath(fRel) {
return nil
}
r.add(fRel, &matches)
return nil
})
if err != nil {
return nil, err
}
} else {
r.add(rel, &matches)
}
}
return matches, nil
}
// WalkAll 遍历全库并过滤
func (r *Resolver) WalkAll() ([]string, error) {
var result []string
ig, _ := tree.Load(r.root)
err := filepath.Walk(r.root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if info.IsDir() && info.Name() == ".git" {
return filepath.SkipDir
}
rel, _ := filepath.Rel(r.root, path)
if ig != nil && ig.MatchesPath(rel) {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
if info.IsDir() {
return nil
}
r.add(rel, &result)
return nil
})
return result, err
}
func (r *Resolver) AddFile(path string, result *[]string) {
r.add(path, result)
}
func (r *Resolver) add(path string, result *[]string) {
if _, ok := r.seen[path]; ok {
return
}
r.seen[path] = struct{}{}
*result = append(*result, path)
}
func (r *Resolver) Unique(in []string) []string {
seen := make(map[string]struct{})
out := make([]string, 0, len(in))
for _, f := range in {
if _, ok := seen[f]; ok {
continue
}
seen[f] = struct{}{}
out = append(out, f)
}
return out
}
+6 -38
View File
@@ -3,52 +3,20 @@ package utils
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings" // "strings"
) )
func ExpandGlob(patterns []string) ([]string, error) { func ExpandGlob(patterns []string) ([]string, error) {
var result []string var result []string
seen := make(map[string]struct{})
for _, pattern := range patterns { for _, pattern := range patterns {
if pattern == "*" { if pattern == "*" {
filepath.Walk(".", func(path string, info os.FileInfo, err error) error { files, err := filepath.Glob("**") // fallback
if err != nil { if err != nil {
return nil return nil, err
}
if info.IsDir() {
return nil
}
add(path, seen, &result)
return nil
})
continue
}
isRecursive := strings.Contains(pattern, "**")
if isRecursive {
root := strings.Split(pattern, "**")[0]
if root == "" {
root = "."
} }
result = append(result, files...)
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return nil
}
matched, _ := filepath.Match(
strings.Replace(pattern, "**", "*", 1),
path,
)
if matched {
add(path, seen, &result)
}
return nil
})
continue continue
} }
@@ -62,7 +30,7 @@ func ExpandGlob(patterns []string) ([]string, error) {
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
continue continue
} }
add(m, seen, &result) result = append(result, m)
} }
} }