mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-12 11:15:00 +02:00
118 lines
2.6 KiB
Go
118 lines
2.6 KiB
Go
package mergeconflicts
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
// LineType tells us whether a given line is a start/middle/end marker of a conflict,
|
|
// or if it's not a marker at all
|
|
type LineType int
|
|
|
|
const (
|
|
START LineType = iota
|
|
ANCESTOR
|
|
TARGET
|
|
END
|
|
NOT_A_MARKER
|
|
)
|
|
|
|
func findConflicts(content string) []*mergeConflict {
|
|
conflicts := make([]*mergeConflict, 0)
|
|
|
|
if content == "" {
|
|
return conflicts
|
|
}
|
|
|
|
var newConflict *mergeConflict
|
|
for i, line := range utils.SplitLines(content) {
|
|
switch determineLineType(line) {
|
|
case START:
|
|
newConflict = &mergeConflict{start: i, ancestor: -1}
|
|
case ANCESTOR:
|
|
if newConflict != nil {
|
|
newConflict.ancestor = i
|
|
}
|
|
case TARGET:
|
|
if newConflict != nil {
|
|
newConflict.target = i
|
|
}
|
|
case END:
|
|
if newConflict != nil {
|
|
newConflict.end = i
|
|
conflicts = append(conflicts, newConflict)
|
|
}
|
|
// reset value to avoid any possible silent mutations in further iterations
|
|
newConflict = nil
|
|
default:
|
|
// line isn't a merge conflict marker so we just continue
|
|
}
|
|
}
|
|
|
|
return conflicts
|
|
}
|
|
|
|
var (
|
|
CONFLICT_START = "<<<<<<< "
|
|
CONFLICT_END = ">>>>>>> "
|
|
CONFLICT_START_BYTES = []byte(CONFLICT_START)
|
|
CONFLICT_END_BYTES = []byte(CONFLICT_END)
|
|
)
|
|
|
|
func determineLineType(line string) LineType {
|
|
// TODO: find out whether we ever actually get this prefix
|
|
trimmedLine := strings.TrimPrefix(line, "++")
|
|
|
|
switch {
|
|
case strings.HasPrefix(trimmedLine, CONFLICT_START):
|
|
return START
|
|
case strings.HasPrefix(trimmedLine, "||||||| "):
|
|
return ANCESTOR
|
|
case trimmedLine == "=======":
|
|
return TARGET
|
|
case strings.HasPrefix(trimmedLine, CONFLICT_END):
|
|
return END
|
|
default:
|
|
return NOT_A_MARKER
|
|
}
|
|
}
|
|
|
|
// tells us whether a file actually has inline merge conflicts. We need to run this
|
|
// because git will continue showing a status of 'UU' even after the conflicts have
|
|
// been resolved in the user's editor
|
|
func FileHasConflictMarkers(path string) (bool, error) {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
return fileHasConflictMarkersAux(file), nil
|
|
}
|
|
|
|
// Efficiently scans through a file looking for merge conflict markers. Returns true if it does
|
|
func fileHasConflictMarkersAux(file io.Reader) bool {
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Split(bufio.ScanLines)
|
|
for scanner.Scan() {
|
|
line := scanner.Bytes()
|
|
|
|
// only searching for start/end markers because the others are more ambiguous
|
|
if bytes.HasPrefix(line, CONFLICT_START_BYTES) {
|
|
return true
|
|
}
|
|
|
|
if bytes.HasPrefix(line, CONFLICT_END_BYTES) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|