Files

100 lines
2.0 KiB
Go
Raw Permalink Normal View History

2026-10-26 02:32:03 +00:00
package buffer
import (
"bytes"
"fmt"
"log/slog"
"os"
"time"
"code.chimeric.al/dwrz/wen/internal/editor/buffer/line"
)
type Buffer struct {
cursor *Cursor
lines []*line.Line
log *slog.Logger
name string
offset *offset
saved time.Time
}
// offset is the 0-indexed first visible display column (glyph) and row (line)
// of the buffer viewport.
type offset struct {
glyph int
line int
}
func (b *Buffer) CursorLine() *line.Line {
return b.lines[b.cursor.line]
}
func (b *Buffer) Name() string {
return b.name
}
type NewBufferParams struct {
Name string
Log *slog.Logger
}
// Create creates or truncates the named file on disk.
// It returns a Buffer initialized with a single empty line,
// so CursorLine is always valid.
func Create(p NewBufferParams) (*Buffer, error) {
var b = &Buffer{
cursor: &Cursor{},
lines: []*line.Line{{}},
log: p.Log,
name: p.Name,
offset: &offset{},
}
// Create the file.
f, err := os.Create(b.name)
if err != nil {
return nil, fmt.Errorf("failed to create file: %w", err)
}
if err := f.Close(); err != nil {
return nil, fmt.Errorf("failed to close file: %w", err)
}
return b, nil
}
// Open reads the named file into a Buffer. If the file is empty, the Buffer
// is initialized with a single empty line so CursorLine is always valid.
func Open(p NewBufferParams) (*Buffer, error) {
var b = &Buffer{
cursor: &Cursor{},
lines: []*line.Line{},
log: p.Log,
name: p.Name,
offset: &offset{},
}
data, err := os.ReadFile(b.name)
if err != nil {
return nil, fmt.Errorf("failed to open file: %w", err)
}
// Trim a single trailing newline so saving doesn't add an extra blank line.
data = bytes.TrimSuffix(data, []byte("\n"))
data = bytes.TrimSuffix(data, []byte("\r"))
if len(data) > 0 {
for _, raw := range bytes.Split(data, []byte("\n")) {
raw = bytes.TrimSuffix(raw, []byte("\r"))
b.lines = append(b.lines, line.New(string(raw)))
}
}
// Add a line to write in, if the file is empty.
if len(b.lines) == 0 {
b.lines = append(b.lines, &line.Line{})
}
return b, nil
}