wip
This commit is contained in:
@@ -68,13 +68,13 @@ func (d Delta) nRows() uint {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Delta) rows() uint {
|
func (d Delta) rows() int {
|
||||||
r := d.End.Row - d.Start.Row
|
r := int(d.End.Row) - int(d.Start.Row)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Delta) cols() uint {
|
func (d Delta) cols() int {
|
||||||
r := d.End.Column
|
r := int(d.End.Column) - int(d.Start.Column)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +82,10 @@ func (d *Document) Contents() string {
|
|||||||
d.mtx.RLock()
|
d.mtx.RLock()
|
||||||
defer d.mtx.RUnlock()
|
defer d.mtx.RUnlock()
|
||||||
|
|
||||||
|
return d.contents()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) contents() string {
|
||||||
return strings.Join(d.lines, "\n")
|
return strings.Join(d.lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+284
-1
@@ -1,7 +1,290 @@
|
|||||||
package acedoc
|
package acedoc
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDelta2(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"b"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "ab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"c"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "abc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "abcd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 5
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"e"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "abcde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 5
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 6
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"f"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "abcdef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "ab\ncdef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "ab\n\ncdef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"action": "remove",
|
||||||
|
"lines": [
|
||||||
|
"d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "ab\n\ncef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"action": "remove",
|
||||||
|
"lines": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "ab\ncef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 0,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "\nab\ncef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 3,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "\nab\ncef\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 3,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 3,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"action": "insert",
|
||||||
|
"lines": [
|
||||||
|
"m"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "\nab\ncef\nm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delta": {
|
||||||
|
"start": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"row": 2,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"action": "remove",
|
||||||
|
"lines": [
|
||||||
|
"c"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"after": "\nab\nef\nm"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
type c struct {
|
||||||
|
After string
|
||||||
|
Delta Delta
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []c{}
|
||||||
|
err := json.Unmarshal([]byte(src), &cases)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc := NewString("")
|
||||||
|
for i, c := range cases {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
before := doc.Contents()
|
||||||
|
|
||||||
|
err := doc.Apply(c.Delta)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if doc.Contents() != c.After {
|
||||||
|
t.Errorf("unexpected output after applying delta %q: %q -> %q, expected: %q", c.Delta, before, doc.Contents(), c.After)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
func TestDelta(t *testing.T) {
|
func TestDelta(t *testing.T) {
|
||||||
type c struct {
|
type c struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package acedoc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,7 +61,6 @@ func (d DeltaAction) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeltaAction) UnmarshalJSON(b []byte) error {
|
func (d *DeltaAction) UnmarshalJSON(b []byte) error {
|
||||||
fmt.Println(string(b))
|
|
||||||
if string(b) == "null" {
|
if string(b) == "null" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -81,6 +81,10 @@ type Delta struct {
|
|||||||
source *Client
|
source *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d Delta) String() string {
|
||||||
|
return fmt.Sprintf("%s:%q(%v->%v)", d.Action, strings.Join(d.Lines, "\n"), d.Start, d.End)
|
||||||
|
}
|
||||||
|
|
||||||
func (d Delta) Equal(other Delta) bool {
|
func (d Delta) Equal(other Delta) bool {
|
||||||
if d.Start != other.Start {
|
if d.Start != other.Start {
|
||||||
return false
|
return false
|
||||||
@@ -133,15 +137,18 @@ func (d *Document) applyInsert(dl Delta) {
|
|||||||
|
|
||||||
row := dl.Start.Row
|
row := dl.Start.Row
|
||||||
col := dl.Start.Column
|
col := dl.Start.Column
|
||||||
line := d.lines[row]
|
|
||||||
|
if uint(len(d.lines)) == row {
|
||||||
|
d.lines = append(d.lines, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
line := d.line(row)
|
||||||
|
|
||||||
if dl.nLines() == 1 {
|
if dl.nLines() == 1 {
|
||||||
d.lines[row] = line[:col] + dl.line(0) + line[col:]
|
d.lines[row] = line[:col] + dl.line(0) + line[col:]
|
||||||
} else {
|
} else {
|
||||||
newlines := []string{}
|
newlines := []string{}
|
||||||
if row != 0 {
|
newlines = append(newlines, d.lines[:row]...) // old content
|
||||||
newlines = append(newlines, d.lines[:row-1]...) // old content
|
|
||||||
}
|
|
||||||
newlines = append(newlines, d.lines[row][:col]+dl.Lines[0])
|
newlines = append(newlines, d.lines[row][:col]+dl.Lines[0])
|
||||||
newlines = append(newlines, dl.Lines[1:]...) // new content
|
newlines = append(newlines, dl.Lines[1:]...) // new content
|
||||||
newlines[len(newlines)-1] += d.lines[row][col:]
|
newlines[len(newlines)-1] += d.lines[row][col:]
|
||||||
@@ -204,7 +211,7 @@ func (d *Document) Apply(dls ...Delta) error {
|
|||||||
|
|
||||||
func (d *Document) validate(dl Delta) error {
|
func (d *Document) validate(dl Delta) error {
|
||||||
if !d.InDocument(dl.Start) {
|
if !d.InDocument(dl.Start) {
|
||||||
return fmt.Errorf("start is not in document")
|
return fmt.Errorf("start %v is not in document %q", dl.Start, d.contents())
|
||||||
}
|
}
|
||||||
|
|
||||||
if dl.Action == DeltaRemove && !d.InDocument(dl.End) {
|
if dl.Action == DeltaRemove && !d.InDocument(dl.End) {
|
||||||
@@ -217,8 +224,8 @@ func (d *Document) validate(dl Delta) error {
|
|||||||
|
|
||||||
lastDlLine := dl.line(dl.nRows() - 1)
|
lastDlLine := dl.line(dl.nRows() - 1)
|
||||||
|
|
||||||
if uint(len(lastDlLine)) != dl.cols() {
|
if !(len(lastDlLine) == 0 && dl.cols() < 0) && len(lastDlLine) != int(math.Abs(float64(dl.cols()))) {
|
||||||
return fmt.Errorf("delta has %d chars on the final line, but positions show range of %d chars", len(lastDlLine), dl.cols())
|
return fmt.Errorf("delta %v has %d chars on the final line, but positions (%v -> %v) show range of %d chars", dl, len(lastDlLine), dl.Start, dl.End, dl.cols())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user