Hayden Hargreaves d4980c5532
All checks were successful
Run Test Suite / test (push) Successful in 15s
feat: created (tested) program_builder.
Also adjusted some of the IO tests for writing and force writing.
2026-03-10 14:18:20 -07:00

84 lines
2.2 KiB
Go

package command
import (
"bufio"
"fmt"
"os"
"git.gophernest.net/azpect/TextEditor/internal/action"
"git.gophernest.net/azpect/TextEditor/internal/core"
tea "github.com/charmbracelet/bubbletea"
)
func writeBuffer(m action.Model, buf *core.Buffer, args []string, force bool) (tea.Cmd, error) {
// Key Steps:
// - Backup Creation (if backup is set): Copy original to .bak file
// - Line Ending Application: Apply fileformat setting (unix=\n, dos=\r\n, mac=\r)
// - Character Encoding: Convert from internal representation to fileencoding
// - Atomic Write: Write to temporary file first (.swp or similar)
// - Atomic Rename: Rename temp file to target filename (atomic operation)
// - Metadata Update: Clear modified flag, update timestamp
// Safety Mechanisms:
// " Vim's write safety
// 1. Check file permissions
// 2. If file exists and 'writebackup' set:
// - Create backup (.bak)
// 3. Write to temporary file (.swp~)
// 4. Verify write succeeded
// 5. Rename temp to target (atomic)
// 6. Remove backup if 'backup' not set
// 7. Update buffer metadata
// TODO: Implement atomic and safe writes
// Check readonly flag ONLY if not forced with !
if !force && buf.ReadOnly {
return nil, fmt.Errorf("cannot write to 'readonly' buffer")
}
if !force && buf.Type == core.ScatchBuffer {
return nil, fmt.Errorf("cannot write to buffer of type 'ScratchBuffer'")
}
// Get the filename; differs by the type
var filename string
if len(args) > 0 {
filename = args[0]
} else {
if buf.Filename == "" {
return nil, fmt.Errorf("cannot write: no file name provided")
}
filename = buf.Filename
}
file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
if err != nil {
return nil, err
}
defer file.Close()
// Same write operation regardless of where the file came from
var bytes int
// Using a bufio.Writer because its more efficient
writer := bufio.NewWriter(file)
for _, line := range buf.Lines {
n, err := writer.WriteString(line + "\n")
if err != nil {
return nil, err
}
bytes += n
}
if err := writer.Flush(); err != nil {
return nil, err
}
output := fmt.Sprintf("'%s', %dL %db written", filename, buf.LineCount(), bytes)
m.SetCommandOutput(output)
buf.SetModified(false)
return nil, nil
}