Skip to content

Commit e9dbd2c

Browse files
committed
auto-coder: refactor diff formatting and enhance progress bar display
- Added a new `DiffStats` struct to hold statistics about the diff, including added, removed, total, and context lines. - Refactored the `FormatDiff` function to split logic into `calculateDiffStats`, `formatDiffLines`, and `createDiffHeader` for better readability and maintainability. - Updated the progress bar calculation to consider the last non-deleted line and display line numbers and percentage completion. - Added new styles for diff output, including headers, added lines, removed lines, and context lines. - Enhanced the `Success` and `Successf` functions with additional documentation and improved styling for success messages. - Improved the handling of diff line numbers and context in the `formatDiffLines` function. Signed-off-by: codiing-hui <wecoding@yeah.net>
1 parent a7337d7 commit e9dbd2c

File tree

3 files changed

+119
-38
lines changed

3 files changed

+119
-38
lines changed

internal/git/git.go

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import (
66
"os"
77
"os/exec"
88
"path"
9+
"regexp"
910
"strconv"
1011
"strings"
12+
13+
"github.com/coding-hui/ai-terminal/internal/ui/console"
1114
)
1215

1316
const (
@@ -242,71 +245,133 @@ func (c *Command) commit(val string) *exec.Cmd {
242245
)
243246
}
244247

248+
// DiffStats holds statistics about the diff
249+
type DiffStats struct {
250+
Added int
251+
Removed int
252+
Total int
253+
Context int
254+
FileHeader string
255+
}
256+
245257
// FormatDiff formats git diff output with color and stats
246258
func (c *Command) FormatDiff(diffOutput string) string {
247-
lines := strings.Split(diffOutput, "\n")
248-
var formattedLines []string
249-
var stats struct {
250-
added int
251-
removed int
252-
total int
259+
if diffOutput == "" {
260+
return ""
253261
}
254262

255-
// First pass to calculate stats
263+
lines := strings.Split(diffOutput, "\n")
264+
stats := c.calculateDiffStats(lines)
265+
formattedLines := c.formatDiffLines(lines, stats)
266+
267+
header := c.createDiffHeader(stats)
268+
return header + strings.Join(formattedLines, "\n")
269+
}
270+
271+
// calculateDiffStats calculates statistics from diff lines
272+
func (c *Command) calculateDiffStats(lines []string) *DiffStats {
273+
stats := &DiffStats{}
274+
var origLineNum, updatedLineNum int
275+
var lastNonDeleted int
276+
256277
for _, line := range lines {
257278
switch {
279+
case strings.HasPrefix(line, "+++"):
280+
stats.FileHeader = line
258281
case strings.HasPrefix(line, "+"):
259-
stats.added++
260-
stats.total++
282+
stats.Added++
283+
stats.Total++
284+
updatedLineNum++
285+
lastNonDeleted = updatedLineNum
261286
case strings.HasPrefix(line, "-"):
262-
stats.removed++
263-
stats.total++
287+
stats.Removed++
288+
stats.Total++
289+
origLineNum++
264290
case strings.HasPrefix(line, "@@"):
265-
stats.total++
291+
stats.Total++
292+
if matches := regexp.MustCompile(`@@ -(\d+),\d+ \+(\d+),\d+ @@`).FindStringSubmatch(line); len(matches) > 0 {
293+
origLineNum, _ = strconv.Atoi(matches[1])
294+
updatedLineNum, _ = strconv.Atoi(matches[2])
295+
lastNonDeleted = updatedLineNum
296+
}
297+
case strings.HasPrefix(line, " "):
298+
stats.Context++
299+
stats.Total++
300+
origLineNum++
301+
updatedLineNum++
302+
lastNonDeleted = updatedLineNum
266303
}
267304
}
268305

269-
// Create progress bar
270-
progress := c.createProgressBar(stats.added, stats.removed, stats.total)
306+
stats.Context = lastNonDeleted
307+
return stats
308+
}
309+
310+
// formatDiffLines formats diff lines with proper styling
311+
func (c *Command) formatDiffLines(lines []string, stats *DiffStats) []string {
312+
var formattedLines []string
313+
var origLineNum, updatedLineNum int
271314

272-
// Second pass to format lines
273315
for _, line := range lines {
274316
switch {
317+
case strings.HasPrefix(line, "+++") || strings.HasPrefix(line, "---"):
318+
formattedLines = append(formattedLines,
319+
console.StdoutStyles().DiffFileHeader.Render(line))
320+
case strings.HasPrefix(line, "@@"):
321+
formattedLines = append(formattedLines,
322+
console.StdoutStyles().DiffHunkHeader.Render(line))
323+
if matches := regexp.MustCompile(`@@ -(\d+),\d+ \+(\d+),\d+ @@`).FindStringSubmatch(line); len(matches) > 0 {
324+
origLineNum, _ = strconv.Atoi(matches[1])
325+
updatedLineNum, _ = strconv.Atoi(matches[2])
326+
}
275327
case strings.HasPrefix(line, "+"):
276328
formattedLines = append(formattedLines,
277-
fmt.Sprintf("\x1b[32m%s\x1b[0m", line)) // Green for additions
329+
console.StdoutStyles().DiffAdded.Render(fmt.Sprintf("%4d + %s", updatedLineNum, line[1:])))
330+
updatedLineNum++
278331
case strings.HasPrefix(line, "-"):
279332
formattedLines = append(formattedLines,
280-
fmt.Sprintf("\x1b[31m%s\x1b[0m", line)) // Red for deletions
281-
case strings.HasPrefix(line, "@@"):
333+
console.StdoutStyles().DiffRemoved.Render(fmt.Sprintf("%4d - %s", origLineNum, line[1:])))
334+
origLineNum++
335+
case strings.HasPrefix(line, " "):
282336
formattedLines = append(formattedLines,
283-
fmt.Sprintf("\x1b[33m%s\x1b[0m", line)) // Yellow for headers
337+
console.StdoutStyles().DiffContext.Render(fmt.Sprintf("%4d %s", origLineNum, line[1:])))
338+
origLineNum++
339+
updatedLineNum++
284340
default:
285341
formattedLines = append(formattedLines, line)
286342
}
287343
}
288344

289-
// Add header with stats
290-
header := fmt.Sprintf("Changes (%d added, %d removed):\n%s\n",
291-
stats.added, stats.removed, progress)
345+
return formattedLines
346+
}
292347

293-
return header + strings.Join(formattedLines, "\n")
348+
// createDiffHeader creates the header with stats and progress
349+
func (c *Command) createDiffHeader(stats *DiffStats) string {
350+
progress := c.createProgressBar(stats.Added, stats.Removed, stats.Total, stats.Context, stats.Total)
351+
352+
return console.StdoutStyles().DiffHeader.Render(
353+
fmt.Sprintf("Changes (%d added, %d removed, %d unchanged):\n%s\n",
354+
stats.Added, stats.Removed, stats.Context, progress))
294355
}
295356

296-
// createProgressBar generates a visual progress bar for diff stats
297-
func (c *Command) createProgressBar(added, removed, total int) string {
357+
// createProgressBar generates a visual progress bar with line numbers
358+
func (c *Command) createProgressBar(added, removed, total, lastNonDeleted, totalLines int) string {
298359
const barWidth = 30
299-
if total == 0 {
360+
if totalLines == 0 {
300361
return ""
301362
}
302363

303-
addedBlocks := int(float64(added) / float64(total) * barWidth)
304-
removedBlocks := int(float64(removed) / float64(total) * barWidth)
305-
unchangedBlocks := barWidth - addedBlocks - removedBlocks
364+
// Calculate progress based on last non-deleted line
365+
progress := float64(lastNonDeleted) / float64(totalLines)
366+
367+
// Calculate bar segments
368+
filledBlocks := int(progress * barWidth)
369+
emptyBlocks := barWidth - filledBlocks
306370

307-
bar := strings.Repeat("█", addedBlocks) +
308-
strings.Repeat("░", removedBlocks) +
309-
strings.Repeat(" ", unchangedBlocks)
371+
bar := strings.Repeat("█", filledBlocks) +
372+
strings.Repeat(" ", emptyBlocks)
310373

311-
return fmt.Sprintf("[%s] %d changes", bar, total)
374+
percentage := progress * 100
375+
return fmt.Sprintf("%3d / %3d lines [%s] %3.0f%%",
376+
lastNonDeleted, totalLines, bar, percentage)
312377
}

internal/ui/console/styles.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ type Styles struct {
2626
SHA1,
2727
Timeago,
2828
CommitStep,
29-
CommitSuccess lipgloss.Style
29+
CommitSuccess,
30+
DiffHeader,
31+
DiffFileHeader,
32+
DiffHunkHeader,
33+
DiffAdded,
34+
DiffRemoved,
35+
DiffContext lipgloss.Style
3036
}
3137

3238
func MakeStyles(r *lipgloss.Renderer) (s Styles) {
@@ -53,6 +59,14 @@ func MakeStyles(r *lipgloss.Renderer) (s Styles) {
5359
s.CommitStep = r.NewStyle().Foreground(lipgloss.Color("#00CED1")).Bold(true)
5460
s.CommitSuccess = r.NewStyle().Foreground(lipgloss.Color("#32CD32"))
5561

62+
// Diff styles
63+
s.DiffHeader = r.NewStyle().Bold(true)
64+
s.DiffFileHeader = r.NewStyle().Foreground(lipgloss.Color("#00CED1")).Bold(true)
65+
s.DiffHunkHeader = r.NewStyle().Foreground(lipgloss.Color("#888888")).Bold(true)
66+
s.DiffAdded = r.NewStyle().Foreground(lipgloss.Color("#00AA00"))
67+
s.DiffRemoved = r.NewStyle().Foreground(lipgloss.Color("#AA0000"))
68+
s.DiffContext = r.NewStyle().Foreground(lipgloss.Color("#888888"))
69+
5670
return s
5771
}
5872

internal/ui/console/success.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ var successStyle = lipgloss.NewStyle().
1111
PaddingTop(1).
1212
Foreground(lipgloss.Color("2"))
1313

14-
// Success prints a bold green success message with top padding.
15-
// Example: console.Success("Operation completed")
14+
// Success prints a bold green success message with top padding to indicate successful operations.
15+
// The message is styled with a green foreground color and bold text for emphasis.
16+
// Example: console.Success("Operation completed successfully")
1617
func Success(text string) {
1718
fmt.Println(successStyle.Render(text))
1819
}
1920

20-
// Successf prints a formatted bold green success message.
21-
// Example: console.Successf("Processed %d items", count)
21+
// Successf prints a formatted bold green success message with top padding.
22+
// Similar to Success but supports formatting with fmt.Sprintf syntax.
23+
// Example: console.Successf("Successfully processed %d items", count)
2224
func Successf(format string, args ...interface{}) {
2325
fmt.Println(successStyle.Render(fmt.Sprintf(format, args...)))
2426
}

0 commit comments

Comments
 (0)