mirror of
https://github.com/felixangell/phi.git
synced 2024-08-16 11:10:37 +03:00
added piectable
This commit is contained in:
parent
c1b51df9dd
commit
3713dc6300
@ -1 +0,0 @@
|
||||
Subproject commit 4446bac0ef28e0391057ecb181f9eaf823a2b21e
|
55
piecetable/line.go
Normal file
55
piecetable/line.go
Normal file
@ -0,0 +1,55 @@
|
||||
package piecetable
|
||||
|
||||
type Line struct {
|
||||
Buffer string
|
||||
parent *PieceTable
|
||||
mods map[int]bool
|
||||
keys []int
|
||||
}
|
||||
|
||||
func NewLine(data string, parent *PieceTable) *Line {
|
||||
return &Line{
|
||||
data, parent, map[int]bool{}, []int{},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Line) AppendNode(node *PieceNode) {
|
||||
nodeIndex := len(l.parent.nodes)
|
||||
l.mods[nodeIndex] = true
|
||||
l.keys = append(l.keys, nodeIndex)
|
||||
l.parent.nodes = append(l.parent.nodes, node)
|
||||
}
|
||||
|
||||
func (l *Line) Len() int {
|
||||
return len(l.String())
|
||||
}
|
||||
|
||||
func (l *Line) String() string {
|
||||
data := l.Buffer
|
||||
|
||||
for _, keyName := range l.keys {
|
||||
thing, ok := l.mods[keyName]
|
||||
// ?
|
||||
if !ok || !thing {
|
||||
continue
|
||||
}
|
||||
|
||||
mod := l.parent.nodes[keyName]
|
||||
|
||||
if mod.Length >= 0 {
|
||||
|
||||
// append!
|
||||
if mod.Start >= len(data) {
|
||||
data += mod.Data
|
||||
continue
|
||||
}
|
||||
|
||||
fst, end := data[:mod.Start], data[mod.Start:]
|
||||
data = fst + mod.Data + end
|
||||
} else {
|
||||
data = data[:mod.Start-1] + data[mod.Start:]
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
17
piecetable/node.go
Normal file
17
piecetable/node.go
Normal file
@ -0,0 +1,17 @@
|
||||
package piecetable
|
||||
|
||||
type PieceNode struct {
|
||||
Index int
|
||||
Start int
|
||||
Length int
|
||||
Data string
|
||||
}
|
||||
|
||||
func NewPiece(data string, line int, start int) *PieceNode {
|
||||
return &PieceNode{
|
||||
line,
|
||||
start,
|
||||
len(data),
|
||||
data,
|
||||
}
|
||||
}
|
149
piecetable/piecetable_test.go
Normal file
149
piecetable/piecetable_test.go
Normal file
@ -0,0 +1,149 @@
|
||||
package piecetable
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeleteSingle(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := ` my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
|
||||
for i := 0; i < len("this is "); i++ {
|
||||
table.Delete(0, 1)
|
||||
}
|
||||
table.Undo()
|
||||
|
||||
fmt.Println(table.String())
|
||||
|
||||
assert.Equal(t, output, table.String())
|
||||
}
|
||||
|
||||
func TestBadRedo(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := `this is my piece foo table testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
table.Insert("piece table ", 0, 11)
|
||||
table.Undo()
|
||||
table.Redo()
|
||||
|
||||
// no redo history.
|
||||
table.Redo()
|
||||
|
||||
fmt.Println(table.String())
|
||||
|
||||
assert.Equal(t, output, table.String())
|
||||
}
|
||||
|
||||
func TestMultiStringInsertion(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := `this is my piece foo table testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
table.Insert("piece table ", 0, 11)
|
||||
table.Insert("foo ", 0, 17)
|
||||
|
||||
fmt.Println(table.String())
|
||||
|
||||
assert.Equal(t, output, table.String())
|
||||
}
|
||||
|
||||
func TestUndo(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := `this is my piece table testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
table.Insert("piece table ", 0, 11)
|
||||
|
||||
fmt.Println(table.String())
|
||||
assert.Equal(t, output, table.String())
|
||||
|
||||
table.Undo()
|
||||
fmt.Println(table.String())
|
||||
assert.Equal(t, text, table.String())
|
||||
}
|
||||
|
||||
func TestRedo(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := `this is my piece table testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
table.Insert("piece table ", 0, 11)
|
||||
|
||||
fmt.Println(table.String())
|
||||
assert.Equal(t, output, table.String())
|
||||
|
||||
table.Undo()
|
||||
fmt.Println(table.String())
|
||||
assert.Equal(t, text, table.String())
|
||||
|
||||
table.Redo()
|
||||
fmt.Println(table.String())
|
||||
assert.Equal(t, output, table.String())
|
||||
}
|
||||
|
||||
func TestStringInsertion(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
output := `this is my piece table testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
table.Insert("piece table ", 0, 11)
|
||||
|
||||
fmt.Println(table.String())
|
||||
|
||||
assert.Equal(t, output, table.String())
|
||||
}
|
||||
|
||||
func TestPrintDocument(t *testing.T) {
|
||||
text := `this is my testing
|
||||
document i want to see how it fares
|
||||
and all of that fun
|
||||
stuff`
|
||||
|
||||
table := MakePieceTable(text)
|
||||
|
||||
fmt.Println(table.String())
|
||||
|
||||
assert.Equal(t, text, table.String(), "Un-modified piece table output doesn't match value expected")
|
||||
}
|
106
piecetable/table.go
Normal file
106
piecetable/table.go
Normal file
@ -0,0 +1,106 @@
|
||||
package piecetable
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type PieceTable struct {
|
||||
Lines []*Line
|
||||
nodes []*PieceNode
|
||||
redoList []*PieceNode
|
||||
}
|
||||
|
||||
func MakePieceTable(data string) *PieceTable {
|
||||
readStrings := strings.Split(data, "\n")
|
||||
|
||||
lines := make([]*Line, len(readStrings))
|
||||
table := &PieceTable{
|
||||
lines,
|
||||
[]*PieceNode{},
|
||||
[]*PieceNode{},
|
||||
}
|
||||
|
||||
for idx, data := range readStrings {
|
||||
lines[idx] = NewLine(data, table)
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
func (p *PieceTable) Redo() {
|
||||
if len(p.redoList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
action := p.redoList[len(p.redoList)-1]
|
||||
p.redoList = p.redoList[:len(p.redoList)-1]
|
||||
|
||||
actionIndex := len(p.nodes)
|
||||
p.nodes = append(p.nodes, action)
|
||||
|
||||
line := p.Lines[action.Index]
|
||||
line.mods[actionIndex] = true
|
||||
}
|
||||
|
||||
func (p *PieceTable) Undo() {
|
||||
if len(p.nodes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
nodeIndex := len(p.nodes) - 1
|
||||
|
||||
// get the value we pop
|
||||
change := p.nodes[nodeIndex]
|
||||
|
||||
// remove the node index from
|
||||
// the mods (i.e. a dangling
|
||||
// pointer)
|
||||
line := p.Lines[change.Index]
|
||||
delete(line.mods, nodeIndex)
|
||||
|
||||
// pop the most recent change
|
||||
p.nodes = p.nodes[:nodeIndex]
|
||||
|
||||
// append it so we can redo it later if necessary
|
||||
p.redoList = append(p.redoList, change)
|
||||
}
|
||||
|
||||
func (p *PieceTable) Delete(line int, idx int) {
|
||||
node := NewPiece("", line, idx)
|
||||
node.Length = -1
|
||||
p.Lines[line].AppendNode(node)
|
||||
}
|
||||
|
||||
// TODO this builds the line and indexes it.
|
||||
func (p *PieceTable) Index(line int, idx int) rune {
|
||||
r, _ := utf8.DecodeLastRuneInString(p.Lines[line].String()[idx:])
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *PieceTable) Insert(val string, line int, idx int) {
|
||||
node := NewPiece(val, line, idx)
|
||||
p.Lines[line].AppendNode(node)
|
||||
}
|
||||
|
||||
func (p *PieceTable) Line(idx int) string {
|
||||
return p.Lines[idx].String()
|
||||
}
|
||||
|
||||
func (p *PieceTable) String() string {
|
||||
var result string
|
||||
for idx, line := range p.Lines {
|
||||
if idx > 0 {
|
||||
result += string('\n')
|
||||
}
|
||||
result += fmt.Sprintf(line.String())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *PieceTable) Print() {
|
||||
for _, line := range p.Lines {
|
||||
fmt.Println(line.Buffer)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user