mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-31 02:25:35 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			154 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mergeconflicts
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/golang-collections/collections/stack"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/utils"
 | |
| )
 | |
| 
 | |
| type Selection int
 | |
| 
 | |
| const (
 | |
| 	TOP Selection = iota
 | |
| 	BOTTOM
 | |
| 	BOTH
 | |
| )
 | |
| 
 | |
| // mergeConflict : A git conflict with a start middle and end corresponding to line
 | |
| // numbers in the file where the conflict markers appear
 | |
| type mergeConflict struct {
 | |
| 	start  int
 | |
| 	middle int
 | |
| 	end    int
 | |
| }
 | |
| 
 | |
| type State struct {
 | |
| 	sync.Mutex
 | |
| 	conflictIndex int
 | |
| 	conflictTop   bool
 | |
| 	conflicts     []*mergeConflict
 | |
| 	EditHistory   *stack.Stack
 | |
| }
 | |
| 
 | |
| func NewState() *State {
 | |
| 	return &State{
 | |
| 		Mutex:         sync.Mutex{},
 | |
| 		conflictIndex: 0,
 | |
| 		conflictTop:   true,
 | |
| 		conflicts:     []*mergeConflict{},
 | |
| 		EditHistory:   stack.New(),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *State) SelectTopOption() {
 | |
| 	s.conflictTop = true
 | |
| }
 | |
| 
 | |
| func (s *State) SelectBottomOption() {
 | |
| 	s.conflictTop = false
 | |
| }
 | |
| 
 | |
| func (s *State) SelectNextConflict() {
 | |
| 	if s.conflictIndex < len(s.conflicts)-1 {
 | |
| 		s.conflictIndex++
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *State) SelectPrevConflict() {
 | |
| 	if s.conflictIndex > 0 {
 | |
| 		s.conflictIndex--
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *State) PushFileSnapshot(content string) {
 | |
| 	s.EditHistory.Push(content)
 | |
| }
 | |
| 
 | |
| func (s *State) PopFileSnapshot() (string, bool) {
 | |
| 	if s.EditHistory.Len() == 0 {
 | |
| 		return "", false
 | |
| 	}
 | |
| 
 | |
| 	return s.EditHistory.Pop().(string), true
 | |
| }
 | |
| 
 | |
| func (s *State) currentConflict() *mergeConflict {
 | |
| 	if len(s.conflicts) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return s.conflicts[s.conflictIndex]
 | |
| }
 | |
| 
 | |
| func (s *State) SetConflictsFromCat(cat string) {
 | |
| 	s.setConflicts(findConflicts(cat))
 | |
| }
 | |
| 
 | |
| func (s *State) setConflicts(conflicts []*mergeConflict) {
 | |
| 	s.conflicts = conflicts
 | |
| 
 | |
| 	if s.conflictIndex > len(s.conflicts)-1 {
 | |
| 		s.conflictIndex = len(s.conflicts) - 1
 | |
| 	} else if s.conflictIndex < 0 {
 | |
| 		s.conflictIndex = 0
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *State) NoConflicts() bool {
 | |
| 	return len(s.conflicts) == 0
 | |
| }
 | |
| 
 | |
| func (s *State) Selection() Selection {
 | |
| 	if s.conflictTop {
 | |
| 		return TOP
 | |
| 	} else {
 | |
| 		return BOTTOM
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *State) IsFinalConflict() bool {
 | |
| 	return len(s.conflicts) == 1
 | |
| }
 | |
| 
 | |
| func (s *State) Reset() {
 | |
| 	s.EditHistory = stack.New()
 | |
| }
 | |
| 
 | |
| func (s *State) GetConflictMiddle() int {
 | |
| 	return s.currentConflict().middle
 | |
| }
 | |
| 
 | |
| func (s *State) ContentAfterConflictResolve(path string, selection Selection) (bool, string, error) {
 | |
| 	conflict := s.currentConflict()
 | |
| 	if conflict == nil {
 | |
| 		return false, "", nil
 | |
| 	}
 | |
| 
 | |
| 	content := ""
 | |
| 	err := utils.ForEachLineInFile(path, func(line string, i int) {
 | |
| 		if !isIndexToDelete(i, conflict, selection) {
 | |
| 			content += line
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return false, "", err
 | |
| 	}
 | |
| 
 | |
| 	return true, content, nil
 | |
| }
 | |
| 
 | |
| func isIndexToDelete(i int, conflict *mergeConflict, selection Selection) bool {
 | |
| 	isMarkerLine :=
 | |
| 		i == conflict.middle ||
 | |
| 			i == conflict.start ||
 | |
| 			i == conflict.end
 | |
| 
 | |
| 	isUnwantedContent :=
 | |
| 		(selection == BOTTOM && conflict.start < i && i < conflict.middle) ||
 | |
| 			(selection == TOP && conflict.middle < i && i < conflict.end)
 | |
| 
 | |
| 	return isMarkerLine || isUnwantedContent
 | |
| }
 |