feat(processor): integrate config-based comment preservation in git mode

- Load .shush.toml configuration for pattern-based comment preservation
- Add preserved comment tracking and display in dry-run output
- Enhance preview with cyan 'P' indicators for preserved comments
- Add preserved count to summary statistics and totals
- Support both line and block comment preservation based on patterns
This commit is contained in:
carraes
2025-07-05 23:43:59 -03:00
parent f53439ddda
commit 20135b3a7f
+93 -35
View File
@@ -6,19 +6,19 @@ import (
"os" "os"
"strings" "strings"
"github.com/carlosarraes/shush/internal/config"
"github.com/carlosarraes/shush/internal/git" "github.com/carlosarraes/shush/internal/git"
"github.com/carlosarraes/shush/internal/types" "github.com/carlosarraes/shush/internal/types"
"github.com/fatih/color" "github.com/fatih/color"
) )
type GitTotals struct { type GitTotals struct {
FilesProcessed int FilesProcessed int
TotalChanged int TotalChanged int
TotalKept int TotalKept int
TotalPreserved int
} }
func (p *Processor) processGitChanges() error { func (p *Processor) processGitChanges() error {
gitStatus, err := git.DetectRepo() gitStatus, err := git.DetectRepo()
@@ -34,7 +34,6 @@ func (p *Processor) processGitChanges() error {
fmt.Printf("Git repository detected: %s\n", gitStatus.RootDir) fmt.Printf("Git repository detected: %s\n", gitStatus.RootDir)
} }
var changes []git.FileChange var changes []git.FileChange
switch { switch {
case p.cli.ChangesOnly: case p.cli.ChangesOnly:
@@ -59,21 +58,28 @@ func (p *Processor) processGitChanges() error {
return nil return nil
} }
supportedChanges := make([]git.FileChange, 0, len(changes))
for _, change := range changes {
if IsSupportedFile(change.Path) {
supportedChanges = append(supportedChanges, change)
} else if p.cli.Verbose {
fmt.Printf("Skipping unsupported file: %s\n", change.Path)
}
}
if len(supportedChanges) == 0 {
fmt.Println("No supported files found to process")
return nil
}
if p.cli.Verbose { if p.cli.Verbose {
fmt.Printf("Found %d files with changes to process\n", len(changes)) fmt.Printf("Found %d supported files with changes to process\n", len(supportedChanges))
} }
totals := &GitTotals{} totals := &GitTotals{}
for _, change := range supportedChanges {
for _, change := range changes {
if !IsSupportedFile(change.Path) {
if p.cli.Verbose {
fmt.Printf("Skipping unsupported file: %s\n", change.Path)
}
continue
}
if p.cli.Verbose { if p.cli.Verbose {
fmt.Printf("Processing: %s\n", change.Path) fmt.Printf("Processing: %s\n", change.Path)
@@ -93,7 +99,6 @@ func (p *Processor) processGitChanges() error {
totals.FilesProcessed++ totals.FilesProcessed++
} }
if p.cli.DryRun && totals.FilesProcessed > 0 { if p.cli.DryRun && totals.FilesProcessed > 0 {
p.showGitTotals(totals) p.showGitTotals(totals)
} }
@@ -101,13 +106,19 @@ func (p *Processor) processGitChanges() error {
return nil return nil
} }
func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.LineRange) error { func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.LineRange) error {
language, err := DetectLanguage(filename) language, err := DetectLanguage(filename)
if err != nil { if err != nil {
return err return err
} }
cfg, _, err := config.Load()
if err != nil && p.cli.Verbose {
fmt.Printf("Warning: failed to load config, using defaults: %v\n", err)
cfg = config.Default()
}
if p.cli.Verbose { if p.cli.Verbose {
fmt.Printf("Processing %s (language: %s)\n", filename, GetLanguageName(filename)) fmt.Printf("Processing %s (language: %s)\n", filename, GetLanguageName(filename))
if len(lineRanges) == 0 { if len(lineRanges) == 0 {
@@ -117,9 +128,6 @@ func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.
} }
} }
file, err := os.Open(filename) file, err := os.Open(filename)
if err != nil { if err != nil {
return err return err
@@ -136,7 +144,6 @@ func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.
return err return err
} }
if p.cli.Backup { if p.cli.Backup {
if err := p.createBackup(filename); err != nil { if err := p.createBackup(filename); err != nil {
return fmt.Errorf("failed to create backup: %v", err) return fmt.Errorf("failed to create backup: %v", err)
@@ -146,8 +153,7 @@ func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.
} }
} }
processEntireFile := len(lineRanges) == 0
processEntireFile := len(lineRanges) == 0
modified := false modified := false
for i, line := range lines { for i, line := range lines {
@@ -155,7 +161,7 @@ processEntireFile := len(lineRanges) == 0
shouldProcess := processEntireFile || git.IsInLineRanges(lineNum, lineRanges) shouldProcess := processEntireFile || git.IsInLineRanges(lineNum, lineRanges)
if shouldProcess { if shouldProcess {
newLine := p.removeCommentsFromLine(line, language) newLine := p.removeCommentsFromLine(line, language, cfg)
if newLine != line { if newLine != line {
lines[i] = newLine lines[i] = newLine
modified = true modified = true
@@ -163,7 +169,6 @@ processEntireFile := len(lineRanges) == 0
} }
} }
if modified { if modified {
outFile, err := os.Create(filename) outFile, err := os.Create(filename)
if err != nil { if err != nil {
@@ -187,24 +192,28 @@ processEntireFile := len(lineRanges) == 0
return nil return nil
} }
func (p *Processor) removeCommentsFromLine(line string, language types.Language, cfg *config.Config) string {
func (p *Processor) removeCommentsFromLine(line string, language types.Language) string {
result := line result := line
hasChanges := false hasChanges := false
if !p.cli.Block && language.LineComment != "" { if !p.cli.Block && language.LineComment != "" {
if idx := strings.Index(result, language.LineComment); idx != -1 { if idx := strings.Index(result, language.LineComment); idx != -1 {
comment := strings.TrimSpace(result[idx:])
if cfg.ShouldPreserveComment(comment) {
return line
}
result = result[:idx] result = result[:idx]
hasChanges = true hasChanges = true
} }
} }
if !p.cli.Inline && language.BlockComment != nil { if !p.cli.Inline && language.BlockComment != nil {
startComment := language.BlockComment.Start startComment := language.BlockComment.Start
endComment := language.BlockComment.End endComment := language.BlockComment.End
@@ -217,18 +226,28 @@ func (p *Processor) removeCommentsFromLine(line string, language types.Language)
endIdx := strings.Index(result[startIdx:], endComment) endIdx := strings.Index(result[startIdx:], endComment)
if endIdx == -1 { if endIdx == -1 {
comment := strings.TrimSpace(result[startIdx:])
if cfg.ShouldPreserveComment(comment) {
return line
}
result = result[:startIdx] result = result[:startIdx]
hasChanges = true hasChanges = true
break break
} }
blockComment := strings.TrimSpace(result[startIdx:startIdx+endIdx+len(endComment)])
if cfg.ShouldPreserveComment(blockComment) {
return line
}
endIdx += startIdx + len(endComment) endIdx += startIdx + len(endComment)
result = result[:startIdx] + result[endIdx:] result = result[:startIdx] + result[endIdx:]
hasChanges = true hasChanges = true
} }
} }
if hasChanges { if hasChanges {
result = strings.TrimSpace(result) result = strings.TrimSpace(result)
} }
@@ -236,13 +255,18 @@ func (p *Processor) removeCommentsFromLine(line string, language types.Language)
return result return result
} }
func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.LineRange, totals *GitTotals) error { func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.LineRange, totals *GitTotals) error {
language, err := DetectLanguage(filename) language, err := DetectLanguage(filename)
if err != nil { if err != nil {
return err return err
} }
cfg, _, err := config.Load()
if err != nil {
cfg = config.Default()
}
file, err := os.Open(filename) file, err := os.Open(filename)
if err != nil { if err != nil {
return err return err
@@ -267,6 +291,7 @@ func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.L
lineNum := 0 lineNum := 0
keptCount := 0 keptCount := 0
changedCount := 0 changedCount := 0
preservedCount := 0
processEntireFile := len(lineRanges) == 0 processEntireFile := len(lineRanges) == 0
@@ -278,7 +303,7 @@ func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.L
lineNumStr := gray.Sprintf("%4d", lineNum) lineNumStr := gray.Sprintf("%4d", lineNum)
if shouldProcess { if shouldProcess {
newLine := p.removeCommentsFromLine(line, language) newLine := p.removeCommentsFromLine(line, language, cfg)
if newLine != line { if newLine != line {
changedCount++ changedCount++
fmt.Printf("%s %s %s\n", lineNumStr, red.Sprint("~"), red.Sprint(line)) fmt.Printf("%s %s %s\n", lineNumStr, red.Sprint("~"), red.Sprint(line))
@@ -286,8 +311,16 @@ func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.L
fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint("+"), green.Sprint(newLine)) fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint("+"), green.Sprint(newLine))
} }
} else { } else {
keptCount++ // Check if this line has comments that were preserved
fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint(" "), line) hasComment := p.lineHasComment(line, language)
if hasComment {
preservedCount++
cyan := color.New(color.FgCyan)
fmt.Printf("%s %s %s\n", lineNumStr, cyan.Sprint("P"), line)
} else {
keptCount++
fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint(" "), line)
}
} }
} else { } else {
keptCount++ keptCount++
@@ -301,20 +334,42 @@ func (p *Processor) showGitPreviewWithTotals(filename string, lineRanges []git.L
fmt.Printf("\n%s\n", strings.Repeat("-", 50)) fmt.Printf("\n%s\n", strings.Repeat("-", 50))
fmt.Printf("%s %d lines would be changed\n", yellow.Sprint("~"), changedCount) fmt.Printf("%s %d lines would be changed\n", yellow.Sprint("~"), changedCount)
fmt.Printf("%s %d lines would be kept\n\n", green.Sprint("✓"), keptCount) fmt.Printf("%s %d lines would be kept\n", green.Sprint("✓"), keptCount)
if preservedCount > 0 {
cyan := color.New(color.FgCyan)
fmt.Printf("%s %d comments would be preserved\n", cyan.Sprint("P"), preservedCount)
}
fmt.Println()
totals.TotalChanged += changedCount totals.TotalChanged += changedCount
totals.TotalKept += keptCount totals.TotalKept += keptCount
totals.TotalPreserved += preservedCount
return nil return nil
} }
// lineHasComment checks if a line contains comments
func (p *Processor) lineHasComment(line string, language types.Language) bool {
// Check for line comments
if language.LineComment != "" && strings.Contains(line, language.LineComment) {
return true
}
// Check for block comments
if language.BlockComment != nil {
if strings.Contains(line, language.BlockComment.Start) || strings.Contains(line, language.BlockComment.End) {
return true
}
}
return false
}
func (p *Processor) showGitTotals(totals *GitTotals) { func (p *Processor) showGitTotals(totals *GitTotals) {
yellow := color.New(color.FgYellow) yellow := color.New(color.FgYellow)
green := color.New(color.FgGreen) green := color.New(color.FgGreen)
blue := color.New(color.FgBlue) blue := color.New(color.FgBlue)
cyan := color.New(color.FgCyan)
fmt.Printf("\n%s\n", strings.Repeat("=", 60)) fmt.Printf("\n%s\n", strings.Repeat("=", 60))
fmt.Printf("%s\n", blue.Sprint("GIT PROCESSING TOTALS")) fmt.Printf("%s\n", blue.Sprint("GIT PROCESSING TOTALS"))
@@ -322,5 +377,8 @@ func (p *Processor) showGitTotals(totals *GitTotals) {
fmt.Printf("%s %d files processed\n", blue.Sprint("📁"), totals.FilesProcessed) fmt.Printf("%s %d files processed\n", blue.Sprint("📁"), totals.FilesProcessed)
fmt.Printf("%s %d lines would be changed\n", yellow.Sprint("~"), totals.TotalChanged) fmt.Printf("%s %d lines would be changed\n", yellow.Sprint("~"), totals.TotalChanged)
fmt.Printf("%s %d lines would be kept\n", green.Sprint("✓"), totals.TotalKept) fmt.Printf("%s %d lines would be kept\n", green.Sprint("✓"), totals.TotalKept)
if totals.TotalPreserved > 0 {
fmt.Printf("%s %d comments would be preserved\n", cyan.Sprint("P"), totals.TotalPreserved)
}
fmt.Printf("%s\n", strings.Repeat("=", 60)) fmt.Printf("%s\n", strings.Repeat("=", 60))
} }