Skip to content

Commit

Permalink
Refactor: Remove all global state via File structs
Browse files Browse the repository at this point in the history
  • Loading branch information
mkchoi212 committed May 19, 2018
1 parent c69a9bb commit 9dd4809
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 279 deletions.
6 changes: 0 additions & 6 deletions conflict/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,3 @@ func TopLevelPath(cwd string) (string, error) {

return string(strings.Split(stdout, "\n")[0]), nil
}

// DiffLines is incomplete (TODO)
func DiffLines(cwd string) ([]string, error) {
stdout, _, _ := run("git", cwd, "--no-pager", "diff", "--color")
return []string{stdout}, nil
}
114 changes: 84 additions & 30 deletions conflict/conflict.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package conflict

import (
"bytes"
"sort"
"strings"

"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/mkchoi212/fac/color"
)

// Conflict represents a single conflict that may have occurred
type Conflict struct {
Choice int
FileName string
AbsolutePath string
Start int
Middle int
End int
Diff3 []int
File *File

Choice int
Start int
Middle int
End int
Diff3 []int

LocalLines []string
LocalPureLines []string
Expand All @@ -26,9 +31,8 @@ type Conflict struct {
CurrentName string
ForeignName string

TopPeek int
BottomPeek int
DisplayDiff bool
TopPeek int
BottomPeek int
}

// Supported git conflict styles
Expand All @@ -40,6 +44,11 @@ const (
end
)

const (
Local = 1
Incoming = 2
)

// IdentifyStyle identifies the conflict marker style of provided text
func IdentifyStyle(line string) (style int) {
line = strings.TrimSpace(line)
Expand All @@ -61,37 +70,36 @@ func IdentifyStyle(line string) (style int) {
// Valid checks if the parsed conflict has corresponding begin, separator,
// and middle line numbers
func (c *Conflict) Valid() bool {
return c.Middle != 0 && c.End != 0
}

func (c *Conflict) Equal(c2 *Conflict) bool {
return c.AbsolutePath == c2.AbsolutePath && c.Start == c2.Start
return c.File != nil && c.Middle != 0 && c.End != 0
}

func (c *Conflict) ToggleDiff() {
c.DisplayDiff = !(c.DisplayDiff)
// Equal checks if two `Conflict`s are equal
func (c Conflict) Equal(c2 *Conflict) bool {
return c.File.AbsolutePath == c2.File.AbsolutePath && c.Start == c2.Start
}

// Extract extracts lines where conflicts exist
// and corresponding branch names
func (c *Conflict) Extract(lines []string) error {
c.LocalLines = lines[c.Start : c.Middle-1]
c.LocalLines = lines[c.Start+1 : c.Middle]
if len(c.Diff3) != 0 {
sort.Ints(c.Diff3)
diff3Barrier := c.Diff3[0]
c.LocalPureLines = lines[c.Start : diff3Barrier-1]
c.LocalPureLines = lines[c.Start+1 : diff3Barrier]
} else {
c.LocalPureLines = c.LocalLines
}
c.IncomingLines = lines[c.Middle : c.End-1]
c.CurrentName = strings.Split(lines[c.Start-1], " ")[1]
c.ForeignName = strings.Split(lines[c.End-1], " ")[1]
c.IncomingLines = lines[c.Middle+1 : c.End]
c.CurrentName = strings.Split(lines[c.Start], " ")[1]
c.ForeignName = strings.Split(lines[c.End], " ")[1]
return nil
}

// PaddingLines returns top and bottom padding lines based on
// `TopPeek` and `BottomPeek` values
func (c *Conflict) PaddingLines() (topPadding, bottomPadding []string) {
lines := FileLines[c.AbsolutePath]
start, end := c.Start-1, c.End
lines := c.File.Lines
start, end := c.Start, c.End

if c.TopPeek >= start {
c.TopPeek = start
Expand All @@ -115,12 +123,58 @@ func (c *Conflict) PaddingLines() (topPadding, bottomPadding []string) {
return
}

// In finds `Conflict`s that are from the provided file name
func In(fname string, conflicts []Conflict) (res []Conflict) {
for _, c := range conflicts {
if c.AbsolutePath == fname && c.Choice != 0 {
res = append(res, c)
// HighlightSyntax highlights the stored file lines; both local and incoming lines
// The highlighted versions of the lines are stored in Conflict.Colored____Lines
// If the file extension is not supported, no highlights are applied
func (c *Conflict) HighlightSyntax() error {
var lexer chroma.Lexer

if lexer = lexers.Match(c.File.Name); lexer == nil {
for _, block := range [][]string{c.LocalLines, c.IncomingLines} {
if trial := lexers.Analyse(strings.Join(block, "")); trial != nil {
lexer = trial
break
}
}
}
return

if lexer == nil {
lexer = lexers.Fallback
c.ColoredLocalLines = c.LocalLines
c.ColoredIncomingLines = c.IncomingLines
return nil
}

style := styles.Get("emacs")
formatter := formatters.Get("terminal")

var it chroma.Iterator
var err error
buf := new(bytes.Buffer)
var colorLine string

tokenizer:
for i, block := range [][]string{c.LocalLines, c.IncomingLines} {
for _, line := range block {
if IdentifyStyle(line) == diff3 {
colorLine = color.Red(color.Regular, line)
} else {
if it, err = lexer.Tokenise(nil, line); err != nil {
break tokenizer
}
if err = formatter.Format(buf, style, it); err != nil {
break tokenizer
}
colorLine = buf.String()
}

if i == 0 {
c.ColoredLocalLines = append(c.ColoredLocalLines, colorLine)
} else {
c.ColoredIncomingLines = append(c.ColoredIncomingLines, colorLine)
}
buf.Reset()
}
}
return err
}
7 changes: 0 additions & 7 deletions conflict/diff.go

This file was deleted.

91 changes: 91 additions & 0 deletions conflict/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package conflict

import (
"bufio"
"io"
"os"
"strings"
)

// File represents a single file that contains git merge conflicts
type File struct {
AbsolutePath string
Name string
Lines []string
Conflicts []Conflict
}

// readFile reads all lines of a given file
func (f *File) Read() (err error) {
input, err := os.Open(f.AbsolutePath)
if err != nil {
return
}
defer input.Close()

r := bufio.NewReader(input)

for {
data, err := r.ReadBytes('\n')
if err == nil || err == io.EOF {
// gocui currently doesn't support printing \r
line := strings.Replace(string(data), "\r", "", -1)
f.Lines = append(f.Lines, line)
}

if err != nil {
if err != io.EOF {
return err
}
break
}
}

return
}

// WriteChanges writes all the resolved conflicts in a given file
// to the file system.
func (f File) WriteChanges() (err error) {
var replacementLines []string

for _, c := range f.Conflicts {
if c.Choice == Local {
replacementLines = append([]string{}, c.LocalPureLines...)
} else if c.Choice == Incoming {
replacementLines = append([]string{}, c.IncomingLines...)
} else {
continue
}

i := 0
for ; i < len(replacementLines); i++ {
f.Lines[c.Start+i] = replacementLines[i]
}
for ; i <= c.End-c.Start; i++ {
f.Lines[c.Start+i] = ""
}
}

if err = write(f.AbsolutePath, f.Lines); err != nil {
return
}
return
}

func write(absPath string, lines []string) (err error) {
f, err := os.Create(absPath)
if err != nil {
return
}
defer f.Close()

w := bufio.NewWriter(f)
for _, line := range lines {
if _, err = w.WriteString(line); err != nil {
return
}
}
err = w.Flush()
return
}
Loading

0 comments on commit 9dd4809

Please sign in to comment.