Skip to content

Commit

Permalink
feat: Support color diff output (#2)
Browse files Browse the repository at this point in the history
Add support for displaying `diff` colored output.
  • Loading branch information
nieomylnieja authored Jul 30, 2024
1 parent 676a709 commit af0b01e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ make build
./bin/gitsync ./go.mod
```

### Requirements

The following programs must be installed and available in the `$PATH`:

- `git`
- `diff` (GNU version)
- `gh` (GitHub CLI)

## Usage

`gitsync` ships with two commands:
Expand Down
27 changes: 24 additions & 3 deletions internal/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package diff
import (
"bufio"
"io"
"regexp"
"strings"

"github.com/pkg/errors"
Expand All @@ -18,12 +19,16 @@ type UnifiedFormat struct {
Hunks []Hunk
}

func (u UnifiedFormat) String() string {
func (u UnifiedFormat) String(original bool) string {
var sb strings.Builder
sb.WriteString(u.Header)
sb.WriteString("\n")
for _, hunk := range u.Hunks {
sb.WriteString(hunk.String())
if original {
sb.WriteString(hunk.Original)
} else {
sb.WriteString(hunk.String())
}
}
return sb.String()
}
Expand All @@ -34,6 +39,9 @@ type Hunk struct {
Lines string `json:"lines"`
// Changes contains only the changed lines, without any context.
Changes []string `json:"changes"`
// Original is the original string representation of the hunk.
// It may include color codes.
Original string `json:"-"`
}

func (h Hunk) String() string {
Expand All @@ -59,22 +67,35 @@ func (h Hunk) Equal(other Hunk) bool {
return true
}

var colorCodeRegex = regexp.MustCompile(`\x1b\[\d+m(?P<content>.*)\x1b\[\d+m`)

func ParseDiffOutput(output io.Reader) (*UnifiedFormat, error) {
uf := &UnifiedFormat{}
scan := bufio.NewScanner(output)
hunkIndex := -1

stripColorCodes := func(line string) string {
return colorCodeRegex.ReplaceAllString(line, "${content}")
}

for scan.Scan() {
line := scan.Text()
originalLine := line
line = stripColorCodes(line)
switch {
case strings.HasPrefix(line, "---"):
uf.Header += line + "\n"
case strings.HasPrefix(line, "+++"):
uf.Header += line
case strings.HasPrefix(line, "@@"):
uf.Hunks = append(uf.Hunks, Hunk{Lines: line})
uf.Hunks = append(uf.Hunks, Hunk{Lines: line, Original: originalLine + "\n"})
hunkIndex++
default:
if hunkIndex == -1 {
return nil, errors.New("invalid diff output, missing hunk header")
}
uf.Hunks[hunkIndex].Changes = append(uf.Hunks[hunkIndex].Changes, line)
uf.Hunks[hunkIndex].Original += originalLine + "\n"
}
}
if err := scan.Err(); err != nil {
Expand Down
9 changes: 7 additions & 2 deletions internal/gitsync/gitsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func syncRepoFile(
}
args := []string{
"-U", "0",
"--color=always",
"--label", fmt.Sprintf("%s (synced): %s (%s)", syncedRepo.Name, file.Path, file.Name),
"--label", fmt.Sprintf("%s (root): %s (%s)", conf.Root.Name, file.Path, file.Name),
}
Expand Down Expand Up @@ -139,7 +140,7 @@ hunkLoop:
}

sep := getPrintSeparator(append(hunk.Changes, strings.Split(unifiedFmt.Header, "\n")...))
fmt.Printf("%[1]s\n%[2]s\n%[3]s%[1]s\n", sep, unifiedFmt.Header, hunk.String())
fmt.Printf("%[1]s\n%[2]s\n%[3]s%[1]s\n", sep, unifiedFmt.Header, hunk.Original)
fmt.Print(promptMessage)
for scanner.Scan() {
switch scanner.Text() {
Expand All @@ -165,13 +166,14 @@ hunkLoop:
if len(unifiedFmt.Hunks) == 0 {
return false, nil
}
patch := unifiedFmt.String()
switch command {
case CommandDiff:
patch := unifiedFmt.String(true)
sep := getPrintSeparator(strings.Split(patch, "\n"))
fmt.Printf("%s\n%s", sep, patch)
return false, nil
case CommandSync:
patch := unifiedFmt.String(false)
if err = applyPatch(syncedRepoFilePath, patch); err != nil {
return false, err
}
Expand Down Expand Up @@ -395,5 +397,8 @@ func checkDependencies() error {
if _, err := execCmd("gh", "--version"); err != nil {
return errors.New("'gh' (GitHub CLI) is required to be installed")
}
if _, err := execCmd("diff", "--version"); err != nil {
return errors.New("'diff' (GNU) is required to be installed")
}
return nil
}

0 comments on commit af0b01e

Please sign in to comment.