Skip to content

Commit 5290551

Browse files
authored
Merge pull request #14 from chojs23/chore/refactor
chore : refactor
2 parents 6eb9ded + 063d683 commit 5290551

File tree

9 files changed

+220
-721
lines changed

9 files changed

+220
-721
lines changed

internal/engine/state.go

Lines changed: 8 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,20 @@
11
package engine
22

33
import (
4-
"bytes"
54
"fmt"
65

76
"github.com/chojs23/ec/internal/markers"
87
)
98

10-
// State manages resolution state for a conflict document with undo support.
9+
// State manages resolution state for a conflict document.
1110
type State struct {
12-
doc markers.Document
13-
undoStack []markers.Document
14-
redoStack []markers.Document
15-
maxUndoSize int
11+
doc markers.Document
1612
}
1713

1814
// NewState creates a new State from a parsed document.
19-
// maxUndoSize controls how many undo operations to retain (must be >= 1).
20-
func NewState(doc markers.Document, maxUndoSize int) (*State, error) {
21-
if maxUndoSize < 1 {
22-
return nil, fmt.Errorf("maxUndoSize must be >= 1, got %d", maxUndoSize)
23-
}
15+
func NewState(doc markers.Document) (*State, error) {
2416
return &State{
25-
doc: doc,
26-
undoStack: make([]markers.Document, 0, maxUndoSize),
27-
redoStack: make([]markers.Document, 0, maxUndoSize),
28-
maxUndoSize: maxUndoSize,
17+
doc: doc,
2918
}, nil
3019
}
3120

@@ -54,9 +43,6 @@ func (s *State) ApplyResolution(conflictIndex int, resolution markers.Resolution
5443
return nil
5544
}
5645

57-
// Save current state to undo stack before modifying, and invalidate redo history.
58-
s.beginMutation()
59-
6046
seg.Resolution = resolution
6147
s.doc.Segments[ref.SegmentIndex] = seg
6248

@@ -88,9 +74,6 @@ func (s *State) ApplyAll(resolution markers.Resolution) error {
8874
return nil
8975
}
9076

91-
// Save current state to undo stack before modifying, and invalidate redo history.
92-
s.beginMutation()
93-
9477
for _, ref := range s.doc.Conflicts {
9578
seg, ok := s.doc.Segments[ref.SegmentIndex].(markers.ConflictSegment)
9679
if !ok {
@@ -103,55 +86,12 @@ func (s *State) ApplyAll(resolution markers.Resolution) error {
10386
return nil
10487
}
10588

106-
// Undo restores the previous state.
107-
// Returns error if no undo history is available.
108-
func (s *State) Undo() error {
109-
if len(s.undoStack) == 0 {
110-
return fmt.Errorf("no undo history available")
111-
}
112-
113-
// Save current state to redo stack before restoring previous state.
114-
s.pushWithLimit(&s.redoStack, s.doc)
115-
116-
// Pop the last state
117-
lastIdx := len(s.undoStack) - 1
118-
s.doc = s.undoStack[lastIdx]
119-
s.undoStack = s.undoStack[:lastIdx]
120-
121-
return nil
122-
}
123-
124-
// Redo reapplies a previously undone state.
125-
// Returns error if no redo history is available.
126-
func (s *State) Redo() error {
127-
if len(s.redoStack) == 0 {
128-
return fmt.Errorf("no redo history available")
129-
}
130-
131-
// Save current state to undo stack before restoring redone state.
132-
s.pushWithLimit(&s.undoStack, s.doc)
133-
134-
lastIdx := len(s.redoStack) - 1
135-
s.doc = s.redoStack[lastIdx]
136-
s.redoStack = s.redoStack[:lastIdx]
137-
138-
return nil
139-
}
140-
141-
// ReplaceDocument replaces the current document as a single undoable mutation.
142-
// If the incoming document is identical to current state, no history is added.
89+
// ReplaceDocument replaces the current document.
14390
func (s *State) ReplaceDocument(doc markers.Document) {
144-
if documentsEqual(s.doc, doc) {
91+
if markers.DocumentsEqual(s.doc, doc) {
14592
return
14693
}
147-
s.beginMutation()
148-
s.doc = cloneDocument(doc)
149-
}
150-
151-
// PushUndoPoint records the current state as an undo step.
152-
// Useful for undoable metadata changes outside Document.
153-
func (s *State) PushUndoPoint() {
154-
s.beginMutation()
94+
s.doc = markers.CloneDocument(doc)
15595
}
15696

15797
// Preview generates the resolved output by concatenating segments with resolutions applied.
@@ -161,90 +101,6 @@ func (s *State) Preview() ([]byte, error) {
161101
return markers.RenderResolved(s.doc)
162102
}
163103

164-
// Document returns a copy of the current document state.
165104
func (s *State) Document() markers.Document {
166-
return s.doc
167-
}
168-
169-
// UndoDepth returns the current number of undo operations available.
170-
func (s *State) UndoDepth() int {
171-
return len(s.undoStack)
172-
}
173-
174-
// RedoDepth returns the current number of redo operations available.
175-
func (s *State) RedoDepth() int {
176-
return len(s.redoStack)
177-
}
178-
179-
// beginMutation saves the current state to undo and clears redo history.
180-
func (s *State) beginMutation() {
181-
s.pushWithLimit(&s.undoStack, s.doc)
182-
s.redoStack = s.redoStack[:0]
183-
}
184-
185-
// pushWithLimit saves a document snapshot into the stack and enforces max size.
186-
func (s *State) pushWithLimit(stack *[]markers.Document, doc markers.Document) {
187-
*stack = append(*stack, cloneDocument(doc))
188-
if len(*stack) > s.maxUndoSize {
189-
*stack = (*stack)[1:]
190-
}
191-
}
192-
193-
func cloneDocument(doc markers.Document) markers.Document {
194-
// Deep copy the document to preserve state
195-
docCopy := markers.Document{
196-
Segments: make([]markers.Segment, len(doc.Segments)),
197-
Conflicts: make([]markers.ConflictRef, len(doc.Conflicts)),
198-
}
199-
200-
for i, seg := range doc.Segments {
201-
switch v := seg.(type) {
202-
case markers.TextSegment:
203-
// TextSegment.Bytes is immutable (we never modify it), so shallow copy is safe
204-
docCopy.Segments[i] = v
205-
case markers.ConflictSegment:
206-
// ConflictSegment fields are immutable byte slices and Resolution enum, shallow copy is safe
207-
docCopy.Segments[i] = v
208-
}
209-
}
210-
211-
copy(docCopy.Conflicts, doc.Conflicts)
212-
return docCopy
213-
}
214-
215-
func documentsEqual(left, right markers.Document) bool {
216-
if len(left.Conflicts) != len(right.Conflicts) || len(left.Segments) != len(right.Segments) {
217-
return false
218-
}
219-
for i := range left.Conflicts {
220-
if left.Conflicts[i] != right.Conflicts[i] {
221-
return false
222-
}
223-
}
224-
for i := range left.Segments {
225-
switch l := left.Segments[i].(type) {
226-
case markers.TextSegment:
227-
r, ok := right.Segments[i].(markers.TextSegment)
228-
if !ok || !bytes.Equal(l.Bytes, r.Bytes) {
229-
return false
230-
}
231-
case markers.ConflictSegment:
232-
r, ok := right.Segments[i].(markers.ConflictSegment)
233-
if !ok {
234-
return false
235-
}
236-
if !bytes.Equal(l.Ours, r.Ours) || !bytes.Equal(l.Base, r.Base) || !bytes.Equal(l.Theirs, r.Theirs) {
237-
return false
238-
}
239-
if l.OursLabel != r.OursLabel || l.BaseLabel != r.BaseLabel || l.TheirsLabel != r.TheirsLabel {
240-
return false
241-
}
242-
if l.Resolution != r.Resolution {
243-
return false
244-
}
245-
default:
246-
return false
247-
}
248-
}
249-
return true
105+
return markers.CloneDocument(s.doc)
250106
}

0 commit comments

Comments
 (0)