Красена обнови решението на 07.11.2018 15:59 (преди 9 месеца)
+package main
+
+import (
+        "math"
+)
+
+type Editor interface {
+        Insert(position uint, text string) Editor
+        Delete(offset uint, length int) Editor
+        Undo() Editor
+        Redo() Editor
+        String() string
+}
+
+type Buff struct {
+        origin bool
+        offset uint
+        length int
+        text   string
+}
+
+var t []*Buff          // current version of the editor
+var versions [][]*Buff // all version of the editor
+var indexVersion int   // on what version is the editor
+var add Buff           // add buffer
+var posAdd int         // where to add the text in the add buffer
+
+func (b *Buff) Insert(position uint, text string) Editor {
+        a, pos := findPosition(t, position)
+        var before, current, newcurrent, after []*Buff
+        var helpLeft, helpRight *Buff
+        before = t[:a]
+        current = append(current, t[a])
+        after = t[a+1:]
+        add.text = add.text + text
+        helper := &Buff{origin: false, offset: uint(posAdd), length: len(text), text: text}
+        posAdd += len(text)
+        if pos-len(b.String()) > 1 { // if adding is at end and is far from the original text
+                helpLeft = &Buff{origin: true, offset: current[0].offset, length: current[0].length, text: current[0].text}
+                newcurrent = append(newcurrent, helpLeft, helper)
+        } else {
+                helpLeft = &Buff{origin: true, offset: current[0].offset, length: len(current[0].text[:pos]), text: current[0].text[:pos]}
+                helpRight = &Buff{origin: true, offset: helpLeft.offset + uint(helpLeft.length), length: len(current[0].text[pos:]), text: current[0].text[pos:]}
+                newcurrent = append(newcurrent, helpLeft, helper, helpRight)
+        }
+        newAfter := make([]*Buff, len(after))
+        copy(newAfter, after)
+        x := append(before, newcurrent...)
+        x = append(x, newAfter...)
+        t = make([]*Buff, len(x))
+        copy(t, x)
+        versions = append(versions, x)
+        indexVersion += 1
+        return b
+}
+func (b *Buff) Delete(offset uint, length int) Editor {
+        if len(b.String()) < int(offset) { // if the text to be deleted is at offset more than the length of the editor
+                a := &Buff{origin: b.origin, offset: b.offset, length: b.length, text: b.text}
+                t = nil
+                t = append(t, a)
+                versions = append(versions, t)
+                indexVersion += 1
+                return a
+        }
+        var before, current, after []*Buff
+        i, place := findPosition(t, offset)
+        before = t[:i]
+        current = append(current, t[i])
+        after = t[i+1:]
+        if t[i].length >= length { // if the text is inside one buffer
+                helpBefore := &Buff{origin: current[0].origin, offset: current[0].offset, length: len(current[0].text[:place]), text: current[0].text[:place]}
+                helpAfter := &Buff{origin: current[0].origin, offset: uint(helpBefore.length + length), length: len(current[0].text[helpBefore.length+length:]), text: current[0].text[helpBefore.length+length:]}
+                var newcurrent []*Buff
+                newcurrent = append(newcurrent, helpBefore, helpAfter)
+                newAfter := make([]*Buff, len(after))
+                copy(newAfter, after)
+                newBefore := make([]*Buff, len(before))
+                copy(newBefore, before)
+                x := append(newBefore, newcurrent...)
+                x = append(x, newAfter...)
+                t = make([]*Buff, len(x))
+                copy(t, x)
+        } else { // if text to be deleted is in two or more buffers
+                helper := &Buff{origin: current[0].origin, offset: uint(place), length: len(current[0].text[:place]), text: current[0].text[:place]}
+                var newLength int
+                newLength = length - len(current[0].text[i:])
+                var place int
+                for _, val := range after {
+                        if newLength < val.length {
+                                break
+                        } else {
+                                newLength -= len(val.text)
+                                place += 1
+                        }
+                }
+                if place == len(after) && len(after[len(after)-1].text) < newLength { // if we want to delete out of the string
+                        before = append(before, helper)
+                        t = make([]*Buff, len(before))
+                        copy(t, before)
+                } else { //if the text is in the correct buffer
+                        newcurrent := &Buff{origin: after[place].origin, offset: after[place].offset + uint(newLength), length: len(after[place].text[newLength:]), text: after[place].text[newLength:]}
+                        newAfter := after[place+1:]
+                        newBefore := make([]*Buff, len(before))
+                        copy(newBefore, before)
+                        x := append(newBefore, newcurrent)
+                        x = append(x, newAfter...)
+                        t = make([]*Buff, len(x))
+                        copy(t, x)
+                }
+        }
+        versions = append(versions, t)
+        indexVersion += 1
+        return b
+}
+
+func (b *Buff) Undo() Editor {
+        if indexVersion == 0 {
+                return b
+        } else {
+                var cnt int
+                for _, value := range versions {
+                        if cnt == indexVersion-1 {
+                                t = value
+                                break
+                        } else {
+                                cnt += 1
+                        }
+                }
+                indexVersion -= 1
+                return b
+        }
+}
+
+func (b *Buff) Redo() Editor {
+        if indexVersion == len(versions)-1 {
+                return b
+        }
+        var cnt int
+        for _, value := range versions {
+                if cnt == indexVersion+1 {
+                        t = value
+                        break
+                } else {
+                        cnt += 1
+                }
+        }
+        indexVersion += 1
+        return b
+}
+
+func (b *Buff) String() string {
+        var res string
+        for _, value := range t {
+                res = res + value.text
+        }
+        return res
+}
+
+func findPosition(t []*Buff, position uint) (i, place int) {
+        var sum int
+        if position == 0 {
+                return i, int(position)
+        }
+        for _, value := range t {
+                if sum >= int(position) {
+                        break
+                } else {
+                        sum += value.length
+                        i += 1
+                }
+        }
+        sum = int(math.Abs(float64(sum - t[i-1].length)))
+        place = int(math.Abs(float64(sum - int(position))))
+        return i - 1, place
+}
+
+func NewEditor(s string) Editor {
+        var r = &Buff{origin: true, offset: 0, length: len(s), text: s}
+        t = nil
+        t = append(t, r)
+        indexVersion = 0
+        versions = nil
+        versions = append(versions, t)
+        return r
+}
