From 9dd4809cdb18199dbbafedc974f115832cb66252 Mon Sep 17 00:00:00 2001
From: "Mike JS. Choi" <mkchoi212@icloud.com>
Date: Fri, 18 May 2018 09:26:28 -0500
Subject: [PATCH] Refactor: Remove all global state via File structs

---
 conflict/command.go  |   6 --
 conflict/conflict.go | 114 +++++++++++++++++-------
 conflict/diff.go     |   7 --
 conflict/file.go     |  91 +++++++++++++++++++
 conflict/parse.go    | 202 +++++++++++--------------------------------
 layout.go            |  26 +++---
 main.go              |  48 +++++-----
 summary.go           |  52 ++---------
 8 files changed, 267 insertions(+), 279 deletions(-)
 delete mode 100644 conflict/diff.go
 create mode 100644 conflict/file.go

diff --git a/conflict/command.go b/conflict/command.go
index 34d1cec..bd273c6 100644
--- a/conflict/command.go
+++ b/conflict/command.go
@@ -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
-}
diff --git a/conflict/conflict.go b/conflict/conflict.go
index 962778e..c287bf7 100644
--- a/conflict/conflict.go
+++ b/conflict/conflict.go
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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
 }
diff --git a/conflict/diff.go b/conflict/diff.go
deleted file mode 100644
index 9fef039..0000000
--- a/conflict/diff.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package conflict
-
-// Diff is incomplete (TODO)
-func (c *Conflict) Diff() []string {
-	lines, _ := DiffLines("")
-	return lines
-}
diff --git a/conflict/file.go b/conflict/file.go
new file mode 100644
index 0000000..e6de101
--- /dev/null
+++ b/conflict/file.go
@@ -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
+}
diff --git a/conflict/parse.go b/conflict/parse.go
index 9d4a399..288866f 100644
--- a/conflict/parse.go
+++ b/conflict/parse.go
@@ -1,214 +1,112 @@
 package conflict
 
 import (
-	"bufio"
-	"bytes"
 	"errors"
-	"fmt"
-	"io"
-	"os"
 	"path"
 	"strconv"
 	"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"
 )
 
-var FileLines map[string][]string
-
-func (c *Conflict) HighlightSyntax() error {
-	var lexer chroma.Lexer
-
-	if lexer = lexers.Match(c.FileName); lexer == nil {
-		for _, block := range [][]string{c.LocalLines, c.IncomingLines} {
-			fmt.Print(strings.Join(block, "\n"))
-			if trial := lexers.Analyse(strings.Join(block, "")); trial != nil {
-				lexer = trial
-				break
-			}
-		}
-	}
-
-	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
-}
-
-// ReadFile reads all lines of a given file
-func ReadFile(absPath string) ([]string, error) {
-	input, err := os.Open(absPath)
-	if err != nil {
-		return nil, err
-	}
-	defer input.Close()
-
-	r := bufio.NewReader(input)
-	lines := []string{}
-
-	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)
-			lines = append(lines, line)
-		}
-
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-			break
-		}
-	}
-	return lines, nil
-}
-
-func parseGitMarkerInfo(diff string, dict map[string][]int) error {
+func parseGitMarkerInfo(diff string) (fname string, lineNum int, err error) {
 	parts := strings.Split(diff, ":")
 
-	if len(parts) < 3 || !strings.Contains(diff, "marker") {
-		return nil
+	if len(parts) < 3 || !strings.Contains(diff, "leftover conflict marker") {
+		err = errors.New("Line does not contain marker location info")
+		return
 	}
 
 	fname, lineData := string(parts[0]), parts[1]
-
-	if lineNum, err := strconv.Atoi(string(lineData)); err == nil {
-		lines := append(dict[fname], lineNum)
-		dict[fname] = lines
+	if lineNum, err = strconv.Atoi(string(lineData)); err != nil {
+		return
 	}
-	return nil
+	return
 }
 
-func newConflicts(absPath string, fname string, markerLocations []int) ([]Conflict, error) {
-	parsedConflicts := []Conflict{}
-	lines := FileLines[absPath]
-
+func parseConflictsIn(f File, markerLocations []int) (conflicts []Conflict, err error) {
 	var conf Conflict
 
 	for _, lineNum := range markerLocations {
-		line := lines[lineNum-1]
+		line := f.Lines[lineNum-1]
+		index := lineNum - 1
 
 		switch IdentifyStyle(line) {
 		case start:
 			conf = Conflict{}
-			conf.AbsolutePath = absPath
-			conf.FileName = fname
-			conf.Start = lineNum
+			conf.Start = index
 		case separator:
-			conf.Middle = lineNum
+			conf.Middle = index
 		case diff3:
-			conf.Diff3 = append(conf.Diff3, lineNum)
+			conf.Diff3 = append(conf.Diff3, index)
 		case end:
-			conf.End = lineNum
-			parsedConflicts = append(parsedConflicts, conf)
+			conf.End = index
+			conflicts = append(conflicts, conf)
 		default:
 			continue
 		}
 	}
 
-	// Verify all markers are properly parsed/paired
-	for _, c := range parsedConflicts {
+	for i := range conflicts {
+		c := &conflicts[i]
+		c.File = &f
+
 		if !(c.Valid()) {
 			return nil, errors.New("Invalid number of remaining conflict markers")
 		}
+
+		if err = c.Extract(f.Lines); err != nil {
+			return
+		}
+
+		if err = c.HighlightSyntax(); err != nil {
+			return
+		}
 	}
-	return parsedConflicts, nil
+
+	return
 }
 
 // Find runs `git --no-pager diff --check` in order to detect git conflicts
-// If there are no conflicts, it returns a `ErrNoConflict`
-// If there are conflicts, it parses the corresponding files
-func Find(cwd string) ([]Conflict, error) {
-	allConflicts := []Conflict{}
-
-	topPath, ok := TopLevelPath(cwd)
-	if ok != nil {
-		return nil, ok
+// It returns an array of `File`s where each `File` contains conflicts within itself
+// If the parsing fails, it returns an error
+func Find(cwd string) (files []File, err error) {
+	topPath, err := TopLevelPath(cwd)
+	if err != nil {
+		return
 	}
 
-	markerLocations, ok := MarkerLocations(topPath)
-	if ok != nil {
-		return nil, ok
+	markerLocations, err := MarkerLocations(topPath)
+	if err != nil {
+		return
 	}
 
 	markerLocMap := make(map[string][]int)
-	FileLines = make(map[string][]string)
-
 	for _, line := range markerLocations {
 		if len(line) == 0 {
 			continue
 		}
 
-		if err := parseGitMarkerInfo(line, markerLocMap); err != nil {
-			return nil, err
+		fname, line, ok := parseGitMarkerInfo(line)
+		if ok != nil {
+			continue
 		}
+		markerLocMap[fname] = append(markerLocMap[fname], line)
 	}
 
 	for fname := range markerLocMap {
 		absPath := path.Join(topPath, fname)
+		file := File{Name: fname, AbsolutePath: absPath}
 
-		lines, err := ReadFile(absPath)
-		if err != nil {
-			return nil, err
+		if err = file.Read(); err != nil {
+			return
 		}
-		FileLines[absPath] = append(FileLines[absPath], lines...)
 
-		if conflicts, err := newConflicts(absPath, fname, markerLocMap[fname]); err == nil {
-			allConflicts = append(allConflicts, conflicts...)
-		} else {
+		conflicts, err := parseConflictsIn(file, markerLocMap[fname])
+		if err != nil {
 			return nil, err
 		}
-	}
 
-	for i := range allConflicts {
-		fileLines := FileLines[allConflicts[i].AbsolutePath]
-		if err := allConflicts[i].Extract(fileLines); err != nil {
-			return nil, err
-		}
-		if err := allConflicts[i].HighlightSyntax(); err != nil {
-			return nil, err
-		}
+		file.Conflicts = conflicts
+		files = append(files, file)
 	}
-
-	return allConflicts, nil
+	return
 }
diff --git a/layout.go b/layout.go
index f01e6d0..a1f41fc 100644
--- a/layout.go
+++ b/layout.go
@@ -15,10 +15,8 @@ const (
 	Prompt  = "prompt"
 	Input   = "input prompt"
 
-	Local    = 1
-	Incoming = 2
-	Up       = 3
-	Down     = 4
+	Up   = 3
+	Down = 4
 
 	Horizontal = 5
 	Vertical   = -6
@@ -143,12 +141,12 @@ func Select(c *conflict.Conflict, g *gocui.Gui, showHelp bool) error {
 		}
 		v.Clear()
 
-		for idx, conflict := range all {
+		for idx, conflict := range conflicts {
 			var out string
 			if conflict.Choice != 0 {
-				out = color.Green(color.Regular, "✔ %s:%d", conflict.FileName, conflict.Start)
+				out = color.Green(color.Regular, "✔ %s:%d", conflict.File.Name, conflict.Start)
 			} else {
-				out = color.Red(color.Regular, "%d. %s:%d", idx+1, conflict.FileName, conflict.Start)
+				out = color.Red(color.Regular, "%d. %s:%d", idx+1, conflict.File.Name, conflict.Start)
 			}
 
 			if conflict.Equal(c) {
@@ -177,7 +175,7 @@ func Select(c *conflict.Conflict, g *gocui.Gui, showHelp bool) error {
 		printLines(v, top)
 		printLines(v, c.ColoredLocalLines)
 		printLines(v, bottom)
-		if c.Choice == Local {
+		if c.Choice == conflict.Local {
 			v.FgColor = gocui.ColorGreen
 		}
 
@@ -192,7 +190,7 @@ func Select(c *conflict.Conflict, g *gocui.Gui, showHelp bool) error {
 		printLines(v, top)
 		printLines(v, c.ColoredIncomingLines)
 		printLines(v, bottom)
-		if c.Choice == Incoming {
+		if c.Choice == conflict.Incoming {
 			v.FgColor = gocui.ColorGreen
 		}
 
@@ -220,22 +218,22 @@ func MoveToItem(dir int, g *gocui.Gui, v *gocui.View) error {
 			cur++
 		}
 
-		if cur >= numConflicts {
+		if cur >= len(conflicts) {
 			cur = 0
 		} else if cur < 0 {
-			cur = numConflicts - 1
+			cur = len(conflicts) - 1
 		}
 
-		if all[cur].Choice == 0 || originalCur == cur {
+		if conflicts[cur].Choice == 0 || originalCur == cur {
 			break
 		}
 	}
 
-	if originalCur == cur && all[cur].Choice != 0 {
+	if originalCur == cur && conflicts[cur].Choice != 0 {
 		globalQuit(g)
 	}
 
-	Select(&all[cur], g, false)
+	Select(conflicts[cur], g, false)
 	return nil
 }
 
diff --git a/main.go b/main.go
index 0b4028a..bf7c01b 100644
--- a/main.go
+++ b/main.go
@@ -12,9 +12,8 @@ import (
 )
 
 var (
+	conflicts        = []*conflict.Conflict{}
 	cur              = 0
-	all              = []conflict.Conflict{}
-	numConflicts     = 0
 	consecutiveError = 0
 )
 
@@ -32,19 +31,19 @@ func parseInput(g *gocui.Gui, v *gocui.View) error {
 	evalCmd := func(in rune, g *gocui.Gui) {
 		switch in {
 		case 'j':
-			Scroll(g, &all[cur], Up)
+			Scroll(g, conflicts[cur], Up)
 		case 'k':
-			Scroll(g, &all[cur], Down)
+			Scroll(g, conflicts[cur], Down)
 		case 'w':
-			all[cur].TopPeek++
-			Select(&all[cur], g, false)
+			conflicts[cur].TopPeek++
+			Select(conflicts[cur], g, false)
 		case 's':
-			all[cur].BottomPeek++
-			Select(&all[cur], g, false)
+			conflicts[cur].BottomPeek++
+			Select(conflicts[cur], g, false)
 		case 'a':
-			Resolve(&all[cur], g, v, Local)
+			Resolve(conflicts[cur], g, v, conflict.Local)
 		case 'd':
-			Resolve(&all[cur], g, v, Incoming)
+			Resolve(conflicts[cur], g, v, conflict.Incoming)
 		case 'n':
 			MoveToItem(Down, g, v)
 		case 'p':
@@ -53,7 +52,7 @@ func parseInput(g *gocui.Gui, v *gocui.View) error {
 			ViewOrientation = ^ViewOrientation
 			layout(g)
 		case 'h', '?':
-			Select(&all[cur], g, true)
+			Select(conflicts[cur], g, true)
 		case 'q':
 			globalQuit(g)
 		default:
@@ -61,7 +60,7 @@ func parseInput(g *gocui.Gui, v *gocui.View) error {
 			consecutiveError++
 			if consecutiveError == 2 {
 				consecutiveError = 0
-				Select(&all[cur], g, true)
+				Select(conflicts[cur], g, true)
 			}
 			return
 		}
@@ -89,20 +88,26 @@ func parseInput(g *gocui.Gui, v *gocui.View) error {
 }
 
 func main() {
+	// Find and parse conflicts
 	cwd, _ := os.Getwd()
-	conflicts, err := conflict.Find(cwd)
+	files, err := conflict.Find(cwd)
 	if err != nil {
 		fmt.Println(color.Red(color.Regular, err.Error()))
 		return
 	}
-	if len(conflicts) == 0 {
+	if len(files) == 0 {
 		fmt.Println(color.Green(color.Regular, "No conflicts detected 🎉"))
 		return
 	}
 
-	all = conflicts
-	numConflicts = len(conflicts)
+	for i := range files {
+		file := &files[i]
+		for j := range file.Conflicts {
+			conflicts = append(conflicts, &file.Conflicts[j])
+		}
+	}
 
+	// Setup CUI Environment
 	g, err := gocui.NewGui(gocui.OutputNormal)
 	if err != nil {
 		log.Panicln(err)
@@ -117,18 +122,15 @@ func main() {
 		log.Panicln(err)
 	}
 
-	Select(&all[0], g, false)
-
+	// Main UI loop
+	Select(conflicts[0], g, false)
 	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
 		log.Panicln(err)
 	}
-
 	g.Close()
 
-	for absPath := range conflict.FileLines {
-		targetConflicts := conflict.In(absPath, all)
-		finalLines := FinalizeChanges(targetConflicts, conflict.FileLines[absPath])
-		if err = writeChanges(absPath, finalLines); err != nil {
+	for _, file := range files {
+		if err = file.WriteChanges(); err != nil {
 			fmt.Println(color.Red(color.Underline, "%s\n", err))
 		}
 	}
diff --git a/summary.go b/summary.go
index 93e49c8..7fd33d8 100644
--- a/summary.go
+++ b/summary.go
@@ -1,14 +1,11 @@
 package main
 
 import (
-	"bufio"
 	"bytes"
 	"fmt"
-	"os"
 
 	"github.com/jroimartin/gocui"
 	"github.com/mkchoi212/fac/color"
-	"github.com/mkchoi212/fac/conflict"
 )
 
 func printHelp(v *gocui.View) {
@@ -35,63 +32,24 @@ func printSummary() {
 	resolvedCnt := 0
 	var line string
 
-	for _, c := range all {
+	for _, c := range conflicts {
 		if c.Choice != 0 {
-			line = color.Green(color.Regular, "✔ %s: %d", c.FileName, c.Start)
+			line = color.Green(color.Regular, "✔ %s: %d", c.File.Name, c.Start)
 			resolvedCnt++
 		} else {
-			line = color.Red(color.Regular, "✘ %s: %d", c.FileName, c.Start)
+			line = color.Red(color.Regular, "✘ %s: %d", c.File.Name, c.Start)
 		}
 		fmt.Println(line)
 	}
 
 	var buf bytes.Buffer
-	if resolvedCnt != numConflicts {
+	if resolvedCnt != len(conflicts) {
 		buf.WriteString("\nResolved ")
 		buf.WriteString(color.Red(color.Light, "%d ", resolvedCnt))
 		buf.WriteString("conflict(s) out of ")
-		buf.WriteString(color.Red(color.Light, "%d", numConflicts))
+		buf.WriteString(color.Red(color.Light, "%d", len(conflicts)))
 	} else {
 		buf.WriteString(color.Green(color.Regular, "\nFixed All Conflicts 🎉"))
 	}
 	fmt.Println(buf.String())
 }
-
-func writeChanges(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
-}
-
-// FinalizeChanges constructs final lines of the file with conflicts removed
-func FinalizeChanges(conflicts []conflict.Conflict, fileLines []string) []string {
-	var replacementLines []string
-
-	for _, c := range conflicts {
-		if c.Choice == Local {
-			replacementLines = append([]string{}, c.LocalPureLines...)
-		} else {
-			replacementLines = append([]string{}, c.IncomingLines...)
-		}
-		i := 0
-		for ; i < len(replacementLines); i++ {
-			fileLines[c.Start+i-1] = replacementLines[i]
-		}
-		for ; c.End-c.Start >= i; i++ {
-			fileLines[c.Start+i-1] = ""
-		}
-	}
-
-	return fileLines
-}