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 { return size } d.dirty = false 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 }