diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 20:22:09 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 20:22:09 +0100 |
| commit | 5a8dbc6347b3541e84fe669b22c17ad3b715e258 (patch) | |
| tree | b148c450939688caaaeb4adac6f2faa1eaffe649 /buffer.go | |
| download | qwe-editor-5a8dbc6347b3541e84fe669b22c17ad3b715e258.tar.gz | |
Engage!
Diffstat (limited to 'buffer.go')
| -rw-r--r-- | buffer.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/buffer.go b/buffer.go new file mode 100644 index 0000000..30dc35b --- /dev/null +++ b/buffer.go @@ -0,0 +1,108 @@ +package main + +// Data structures and methods for managing a file buffer, its content (lines of +// runes), and multiple cursors. + +import ( + "strings" + "time" +) + +// Cursor represents a position in the buffer. +type Cursor struct { + X int // Column index (0-based). + Y int // Row index (0-based). + PreferredCol int // Remembers the intended column when moving up/down. +} + +// HistoryState stores a snapshot of the buffer and cursors for undo/redo. +type HistoryState struct { + buffer [][]rune + cursors []Cursor +} + +// Buffer represents an open file and its associated editor state. +type Buffer struct { + buffer [][]rune // Slice of lines, where each line is a slice of runes. + cursors []Cursor // Support for multiple cursors. + scrollX int // Horizontal scroll offset. + scrollY int // Vertical scroll offset. + filename string // Path to the file on disk. + modified bool // True if changes haven't been saved. + readOnly bool // True if the buffer cannot be edited. + undoStack []HistoryState // For undo functionality. + redoStack []HistoryState // For redo functionality. + fileType *FileType // Language-specific settings. + lspClient *LSPClient // Associated LSP client for this buffer. + diagnostics []Diagnostic // Errors/warnings for this buffer. + syntax *SyntaxHighlighter // Syntax highlighting engine. + lastModTime time.Time // Last modified time of the file on disk. +} + +// PrimaryCursor returns the first cursor in the list. +func (b *Buffer) PrimaryCursor() *Cursor { + if len(b.cursors) == 0 { + b.cursors = append(b.cursors, Cursor{X: 0, Y: 0}) + } + // The first cursor is usually the main one used for most operations. + return &b.cursors[0] +} + +// AddCursor adds a new cursor at the specified position. +func (b *Buffer) AddCursor(x, y int) { + b.cursors = append(b.cursors, Cursor{X: x, Y: y, PreferredCol: x}) +} + +// ClearCursors removes all cursors except the primary one. +func (b *Buffer) ClearCursors() { + if len(b.cursors) > 1 { + primary := b.cursors[0] + b.cursors = []Cursor{primary} + } +} + +// getLineByteOffset calculates the byte index for a given column in a line of +// runes. +func (b *Buffer) getLineByteOffset(line []rune, col int) uint32 { + // Rune indices != Byte indices for multi-byte characters (UTF-8). + if col > len(line) { + col = len(line) + } + return uint32(len(string(line[:col]))) +} + +// getByteOffset calculates the total byte offset from the start of the buffer +// to (row, col). +func (b *Buffer) getByteOffset(row, col int) uint32 { + var offset uint32 + for i := 0; i < row && i < len(b.buffer); i++ { + offset += uint32(len(string(b.buffer[i]))) + 1 // +1 for the newline character. + } + + if row < len(b.buffer) { + offset += b.getLineByteOffset(b.buffer[row], col) + } + return offset +} + +// toString converts the entire buffer (slice of lines) into a single string. +func (b *Buffer) toString() string { + var result strings.Builder + for i, line := range b.buffer { + result.WriteString(string(line)) + if i < len(b.buffer)-1 { + result.WriteString("\n") + } + } + return result.String() +} + +// handleEdit is a placeholder for incremental syntax highlighting updates. +func (b *Buffer) handleEdit(startRow, startCol int, bytesRemoved, bytesAdded uint32, oldEndRow int, oldEndColBytes uint32, newEndRow int, newEndColBytes uint32) { + if b.syntax == nil { + return + } + + // We batch syntax updates in editor.go via Reparse, so we don't need + // incremental updates here. +} |
