a version with known bug fixed but not sure any more obscure ones
This commit is contained in:
+7
-5
@@ -6,11 +6,13 @@ prompts:
|
||||
|
||||
preset:
|
||||
all:
|
||||
- "cmd/*"
|
||||
- "internal/tree/*"
|
||||
- "internal/utils/*"
|
||||
- "internal/config/*"
|
||||
- "main.go"
|
||||
- "*"
|
||||
# - "cmd/*"
|
||||
# - "internal/tree/*"
|
||||
# - "internal/utils/*"
|
||||
# - "internal/config/*"
|
||||
# - "internal/resolver/*"
|
||||
# - "main.go"
|
||||
|
||||
internal:
|
||||
- "internal/tree/*"
|
||||
|
||||
+63
-14
@@ -4,14 +4,16 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"cliprepo/internal/config"
|
||||
"cliprepo/internal/resolver"
|
||||
"cliprepo/internal/tree"
|
||||
"cliprepo/internal/utils"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var delineate string
|
||||
@@ -35,29 +37,74 @@ var runCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
// builder.WriteString("===== PROJECT TREE =====\n")
|
||||
builder.WriteString(treeStr)
|
||||
builder.WriteString("\n\n")
|
||||
|
||||
// 2. preset files
|
||||
var patterns []string
|
||||
// 2. resolver (GLOBAL FILE REGISTRY)
|
||||
r := resolver.New(".")
|
||||
|
||||
raw, ok := cfg.Preset[delineate]
|
||||
if !ok {
|
||||
return fmt.Errorf("preset not found: %s", delineate)
|
||||
}
|
||||
|
||||
patterns = append(patterns, raw...)
|
||||
patterns := []string(raw)
|
||||
|
||||
files, err := utils.ExpandGlob(patterns)
|
||||
if err != nil {
|
||||
return err
|
||||
var files []string
|
||||
|
||||
for _, pattern := range patterns {
|
||||
|
||||
// =========================
|
||||
// FULL REPO SCAN
|
||||
// =========================
|
||||
if pattern == "*" {
|
||||
all, err := r.WalkAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files = append(files, all...)
|
||||
continue
|
||||
}
|
||||
|
||||
// =========================
|
||||
// recursive glob support
|
||||
// =========================
|
||||
if strings.Contains(pattern, "**") {
|
||||
matches, err := utils.ExpandGlob([]string{pattern})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, m := range matches {
|
||||
r.AddFile(m, &files)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// =========================
|
||||
// normal glob
|
||||
// =========================
|
||||
matches, err := utils.ExpandGlob([]string{pattern})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, m := range matches {
|
||||
r.AddFile(m, &files)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. template
|
||||
template := cfg.Prompts.Preset
|
||||
// 3. dedup + stable order
|
||||
files = r.Unique(files)
|
||||
sort.Strings(files)
|
||||
|
||||
// 4. template
|
||||
template := cfg.Prompts.Preset
|
||||
if template == "" {
|
||||
template = "The following code is from file {{path}}:\n---\n{{content}}"
|
||||
}
|
||||
|
||||
// 5. render
|
||||
for _, file := range files {
|
||||
|
||||
content, err := os.ReadFile(file)
|
||||
@@ -65,13 +112,14 @@ var runCmd = &cobra.Command{
|
||||
continue
|
||||
}
|
||||
|
||||
path := file
|
||||
// 先初始化 filePath 变量,避免作用域及同名包冲突
|
||||
filePath := file
|
||||
if cfg.Config.PathMode == "absolute" {
|
||||
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))
|
||||
|
||||
builder.WriteString(block)
|
||||
@@ -80,6 +128,7 @@ var runCmd = &cobra.Command{
|
||||
|
||||
result := builder.String()
|
||||
|
||||
// 6. output
|
||||
if useClipboard {
|
||||
return clipboard.WriteAll(result)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
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{}),
|
||||
}
|
||||
}
|
||||
|
||||
// WalkAll 遍历所有文件,并自动跳过 .git 和 .gitignore 中的文件
|
||||
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
|
||||
}
|
||||
|
||||
// 显式跳过 .git 目录
|
||||
if info.IsDir() && info.Name() == ".git" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
rel, _ := filepath.Rel(r.root, path)
|
||||
|
||||
// 遵循 .gitignore 规则
|
||||
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)
|
||||
}
|
||||
|
||||
// Unique 保留此方法供 run.go 调用
|
||||
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
@@ -3,52 +3,20 @@ package utils
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
func ExpandGlob(patterns []string) ([]string, error) {
|
||||
var result []string
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
for _, pattern := range patterns {
|
||||
|
||||
if pattern == "*" {
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
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 = "."
|
||||
files, err := filepath.Glob("**") // fallback
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
result = append(result, files...)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -62,7 +30,7 @@ func ExpandGlob(patterns []string) ([]string, error) {
|
||||
if err != nil || info.IsDir() {
|
||||
continue
|
||||
}
|
||||
add(m, seen, &result)
|
||||
result = append(result, m)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user