@@ -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
1316const (
@@ -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
246258func (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}
0 commit comments