1
0
Fork 0
gilo/editor/document/document.go

175 lines
3.0 KiB
Go

package document
import (
"bufio"
"log"
"os"
"timshome.page/gilo/internal/gilo"
)
type Document struct {
dirty bool
Filename string
rows []*Row
}
func NewDocument() *Document {
var rows []*Row
return &Document{
false,
"",
rows,
}
}
func (d *Document) Open(filename string) {
file, err := os.Open(filename)
if err != nil {
log.Fatalf("failed to open file")
}
defer file.Close()
d.Filename = filename
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
d.AppendRow(scanner.Text())
}
d.dirty = false
}
func (d *Document) Save() int {
if d.Filename == "" {
return 0
}
file, err := os.OpenFile(d.Filename, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
panic("failed to open/create file for saving")
}
defer file.Close()
fileStr := d.ToString()
fileLen := len(fileStr)
err = file.Truncate(int64(fileLen))
if err != nil {
panic("failed to truncate file")
}
size, err := file.WriteString(fileStr)
if err != nil {
panic("failed to save Document to file")
}
if fileLen == size {
d.dirty = false
return size
}
return 0
}
func (d *Document) GetRow(at int) *Row {
return d.rows[at]
}
func (d *Document) AppendRow(s string) {
newRow := newRow(s)
newRow.update()
d.rows = append(d.rows, newRow)
d.dirty = true
}
func (d *Document) InsertRow(at int, s string) {
if at < 0 || at > d.RowCount() {
return
}
var newRows []*Row
// Split the array of rows at the specified index
start := d.rows[0:at]
end := d.rows[at:d.RowCount()]
// Splice it back together
newRows = append(newRows, start...)
newRows = append(newRows, newRow(s))
newRows = append(newRows, end...)
d.rows = newRows
d.dirty = true
}
func (d *Document) InsertNewline(at *gilo.Point) {
if at.X == 0 {
d.InsertRow(at.Y, "")
} else {
row := d.rows[at.Y]
// Insert the characters right of the cursor to the next line
d.InsertRow(at.Y+1, string(row.chars[at.X:row.Size()]))
// Remove the characters copied to the next line
row.chars = row.chars[0:at.X]
row.update()
}
}
func (d *Document) MergeRows(to int, from int) {
d.rows[to].appendString(d.rows[from].toString())
d.delRow(from)
}
func (d *Document) ToString() string {
buf := gilo.NewBuffer()
for _, row := range d.rows {
buf.Append(row.toString())
buf.AppendRune('\n')
}
return buf.ToString()
}
func (d *Document) RowCount() int {
return len(d.rows)
}
func (d *Document) InsertChar(at *gilo.Point, ch rune) {
d.rows[at.Y].insertRune(ch, at.X)
d.dirty = true
}
func (d *Document) DelChar(at *gilo.Point) {
d.rows[at.Y].deleteRune(at.X)
d.dirty = true
}
func (d *Document) IsDirty() bool {
return d.dirty
}
func (d *Document) delRow(at int) {
var newSlice []*Row
// Split the array of rows at the specified index
start := d.rows[0:at]
end := d.rows[at+1 : d.RowCount()] // Skip the index in question
// Splice it back together
newSlice = append(newSlice, start...)
newSlice = append(newSlice, end...)
d.rows = newSlice
d.dirty = true
}