Исмаил обнови решението на 04.11.2018 18:14 (преди 9 месеца)
+package main
+
+type Editor interface {
+ // Insert text starting from given position.
+ Insert(position uint, text string) Editor
+
+ // Delete length items from offset.
+ Delete(offset, length uint) Editor
+
+ // Undo reverts latest change.
+ Undo() Editor
+
+ // Redo re-applies latest undone change.
+ Redo() Editor
+
+ // String returns complete representation of what a file looks
+ // like after all manipulations.
+ String() string
+}
+
+func (p PieceTableEditor) String() string {
+ var content []byte
+ for _, piece := range p.state.pieces {
+ if piece.origin {
+ content = append(content, p.origin[piece.offset:piece.offset+piece.length]...)
+ } else {
+ content = append(content, p.add[piece.offset:piece.offset+piece.length]...)
+ }
+ }
+
+ return string(content)
+}
+
+func (p PieceTableEditor) Insert(position uint, text string) Editor {
+ textBytes := []byte(text)
+ additionOffset := len(p.add)
+ p.add = append(p.add, textBytes...)
+
+ counter := 0
+
+ var piecesCopy []Piece
+
+ isAdded := false
+ for _, piece := range p.state.pieces {
+ if int(position) < counter+piece.length && !isAdded {
+ beforeLength := int(position) - piece.offset
+
+ before := Piece{origin: true, offset: piece.offset, length: beforeLength}
+ addition := Piece{origin: false, offset: additionOffset, length: len(textBytes)}
+ after := Piece{origin: true, offset: int(position), length: piece.length - beforeLength}
+
+ piecesCopy = append(piecesCopy, before)
+ piecesCopy = append(piecesCopy, addition)
+ piecesCopy = append(piecesCopy, after)
+
+ isAdded = true
+ } else if int(position) == counter+piece.length && !isAdded {
+ addition := Piece{origin: false, offset: additionOffset, length: len(textBytes)}
+
+ piecesCopy = append(piecesCopy, piece)
+ piecesCopy = append(piecesCopy, addition)
+
+ isAdded = true
+ } else {
+ piecesCopy = append(piecesCopy, piece)
+ }
+
+ counter += piece.length
+ }
+
+ newState := &State{pieces: piecesCopy}
+
+ p.state.next = newState
+ newState.prev = p.state
+ p.state = newState
+
+ return p
+}
+
+func (p PieceTableEditor) Delete(offset, length uint) Editor {
+ var piecesCopy []Piece
+
+ counter := 0
+
+ deleted := false
+ for _, piece := range p.state.pieces {
+ if counter == int(offset) {
+ deletion := Piece{origin: piece.origin, offset: piece.offset + int(length), length: piece.length - int(length)}
+
+ piecesCopy = append(piecesCopy, deletion)
+
+ deleted = true
+ } else if int(offset) < counter+piece.length && !deleted {
+ beforeLength := int(offset) - counter
+ afterOffset := beforeLength + int(length) + piece.offset
+
+ before := Piece{origin: piece.origin, offset: piece.offset, length: beforeLength}
+ after := Piece{origin: piece.origin, offset: afterOffset, length: (piece.length + piece.offset) - afterOffset}
+
+ piecesCopy = append(piecesCopy, before)
+ piecesCopy = append(piecesCopy, after)
+
+ deleted = true
+ } else {
+ piecesCopy = append(piecesCopy, piece)
+ }
+
+ counter += piece.length
+ }
+
+ newState := &State{pieces: piecesCopy}
+
+ p.state.next = newState
+ newState.prev = p.state
+ p.state = newState
+
+ return p
+}
+
+func (p PieceTableEditor) Undo() Editor {
+ prev := p.state.prev
+ if prev != nil {
+ p.state = prev
+ }
+
+ return p
+}
+
+func (p PieceTableEditor) Redo() Editor {
+ next := p.state.next
+ if next != nil {
+ p.state = next
+ }
+
+ return p
+}
+
+type PieceTableEditor struct {
+ origin []byte
+ add []byte
+
+ state *State
+}
+
+type State struct {
+ pieces []Piece
+
+ prev *State
+ next *State
+}
+
+type Piece struct {
+ origin bool
+ offset int
+ length int
+}
+
+func NewEditor(content string) Editor {
+ editor := PieceTableEditor{origin: []byte(content)}
+ piece := Piece{origin: true, offset: 0, length: len(content)}
+
+ var pieces []Piece
+ pieces = append(pieces, piece)
+ editor.state = &State{pieces: pieces}
+
+ return editor
+}