hashline

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package hashline applies edits guarded by content hashes instead of trusting stale offsets alone. It is intentionally exact by default: a hunk only applies when its old bytes hash to the recorded anchor hash and the same span can be found unambiguously in the current source.

Index

Constants

View Source
const (
	// HashHexLength keeps anchors compact while preserving enough entropy for
	// local edit validation. The full SHA-256 is still used before truncation.
	HashHexLength = 16

	// RelocationWindow bounds stale-offset recovery so the matcher stays cheap and
	// does not wander through unrelated repeated code looking for a plausible fit.
	RelocationWindow = 64 * 1024
)
View Source
const MaxEditFileBytes = 64 * 1024 * 1024 // 64 MiB

MaxEditFileBytes bounds how large a file this package will read fully into memory to apply a hash-anchored edit. This is not the same budget as the read tools' receipt-window caps: those bound what one read call returns to the model, while an edit target can be a much larger file than any single read window (offset can start anywhere in it). The bound here exists to reject an implausible target — a stray multi-GB log or data file someone points the tool at — before it is loaded into memory, not to constrain ordinary source files.

Variables

This section is empty.

Functions

func Apply

func Apply(src []byte, hunks []Hunk) ([]byte, error)

Apply validates every hunk against src and returns a new byte slice with all edits applied. The input slice is never modified.

func ApplyFile

func ApplyFile(path string, hunks []Hunk) error

ApplyFile reads path, applies hunks, and replaces the file with a same-directory temp file rename. The same directory keeps the rename on the same filesystem, which gives POSIX platforms atomic replacement semantics for readers.

func ReadFileForEdit

func ReadFileForEdit(path string) ([]byte, error)

ReadFileForEdit reads path as the source of a hash-anchored edit (for Apply, ApplyFile, or a manual Apply+ReplaceFileIfUnchanged sequence), refusing a file over MaxEditFileBytes before it is loaded into memory.

func ReplaceFileIfUnchanged

func ReplaceFileIfUnchanged(path string, expected, content []byte) error

ReplaceFileIfUnchanged atomically replaces path only when it still contains expected.

Types

type Anchor

type Anchor struct {
	Path   string
	Offset int
	Length int
	Hash   string // hex sha256(exact span)[:16]
}

Anchor records the exact byte span observed at read time.

func HashSpan

func HashSpan(src []byte, offset, length int) (Anchor, error)

HashSpan hashes the exact byte span at offset:length and returns a compact anchor. No whitespace normalization is applied; Go and many other languages are whitespace-sensitive, so fuzzy matching must be opt-in in a later layer.

type ApplyError

type ApplyError struct {
	Kind         ErrorKind
	Message      string
	ExpectedHash string
	FoundHash    string
	RereadStart  int
	RereadEnd    int
}

ApplyError carries structured context while still formatting as a plain error for tools that only expose textual failures.

func (*ApplyError) Error

func (e *ApplyError) Error() string

type ErrorKind

type ErrorKind string

ErrorKind identifies structured edit failures for model-facing recovery loops.

const (
	ErrStaleAnchor     ErrorKind = "stale_anchor"
	ErrAmbiguousAnchor ErrorKind = "ambiguous_anchor"
	ErrOverlap         ErrorKind = "overlapping_hunks"
	ErrInvalidText     ErrorKind = "invalid_text"
	ErrInvalidRange    ErrorKind = "invalid_range"
	// ErrEmptyAnchor means a hunk has no old text. An empty span hashes to a
	// constant, so it verifies nothing about the file; anchor on adjacent text.
	ErrEmptyAnchor ErrorKind = "empty_anchor"
	// ErrHashMismatch means the hunk's Old text does not hash to Anchor.Hash.
	// It is distinct from ErrStaleAnchor, which means the input is internally
	// consistent but no longer matches the live source file.
	ErrHashMismatch    ErrorKind = "hash_mismatch"
	ErrInvalidHash     ErrorKind = "invalid_hash"
	ErrConcurrentWrite ErrorKind = "concurrent_write"
)
const ErrFileTooLarge ErrorKind = "file_too_large"

ErrFileTooLarge means the target file exceeds MaxEditFileBytes.

type Hunk

type Hunk struct {
	Anchor Anchor
	Old    []byte // must hash to Anchor.Hash
	New    []byte
}

Hunk replaces Old bytes at Anchor with New bytes after validating the anchor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL