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:
@@ -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,7 +153,6 @@ func (p *Processor) processFileWithLineRanges(filename string, lineRanges []git.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
processEntireFile := len(lineRanges) == 0
|
processEntireFile := len(lineRanges) == 0
|
||||||
modified := false
|
modified := false
|
||||||
|
|
||||||
@@ -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,17 +303,25 @@ 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))
|
||||||
if strings.TrimSpace(newLine) != "" {
|
if strings.TrimSpace(newLine) != "" {
|
||||||
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 {
|
||||||
|
// Check if this line has comments that were preserved
|
||||||
|
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 {
|
} else {
|
||||||
keptCount++
|
keptCount++
|
||||||
fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint(" "), line)
|
fmt.Printf("%s %s %s\n", lineNumStr, green.Sprint(" "), line)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
keptCount++
|
keptCount++
|
||||||
fmt.Printf("%s %s %s\n", lineNumStr, gray.Sprint(" "), gray.Sprint(line))
|
fmt.Printf("%s %s %s\n", lineNumStr, gray.Sprint(" "), gray.Sprint(line))
|
||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user