index

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: May 4, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package index manages the .focus/index.json derived cache.

The index is the read path for every command that doesn't load card bodies — `focus board`, `focus list`, `focus epic list`, the TUI's board view, etc. It holds frontmatter only; bodies are loaded on demand by `focus show`/`focus edit`. This is where the speed win over v1's bash implementation comes from.

Writes go through Save which uses google/renameio/v2 for an atomic temp-file → fsync → rename, so a crash mid-write can never leave a truncated index on disk. All mutating callers must hold the .focus/.lock flock for the duration of the read-modify-write cycle (see internal/board/lock).

Index

Constants

View Source
const FileName = "index.json"

FileName is the index file's name relative to .focus/.

View Source
const SchemaVersion = 2

SchemaVersion is stamped on every index.json we write. Bumped only when the index file format changes in a backwards-incompatible way; independent of the card schema_version.

Variables

This section is empty.

Functions

func Save

func Save(focusDir string, idx *Index) error

Save writes the index to .focus/index.json atomically via renameio/v2 (temp file in the same dir → fsync → rename). The rename is atomic on POSIX, so concurrent readers either see the old snapshot or the new one — never a torn write.

Save also stamps GeneratedAt to the current UTC time and sets SchemaVersion to the constant; callers don't need to fill those.

Sorted by id for stable diffs and deterministic output across platforms.

Types

type Entry

type Entry struct {
	ID          int           `json:"id"`
	UUID        string        `json:"uuid"`
	Title       string        `json:"title"`
	Type        card.Type     `json:"type"`
	Status      card.Status   `json:"status"`
	Priority    card.Priority `json:"priority"`
	Project     string        `json:"project"`
	Epic        *int          `json:"epic,omitempty"`
	Tags        []string      `json:"tags,omitempty"`
	Owner       string        `json:"owner,omitempty"`
	Description string        `json:"description,omitempty"`
	Area        string        `json:"area,omitempty"`
	Created     string        `json:"created"`
	Dir         string        `json:"dir"`
}

Entry is one card's row in the index. Frontmatter only — never the body.

func EntryFromCard

func EntryFromCard(c *card.Card, dir string) Entry

EntryFromCard converts a fully-parsed Card plus its on-disk dir (relative to the board root, e.g. "cards/0142-ship-the-feature") into an index Entry. The body is intentionally dropped.

type Index

type Index struct {
	SchemaVersion int       `json:"schema_version"`
	GeneratedAt   time.Time `json:"generated_at"`
	NextID        int       `json:"next_id"`
	Cards         []Entry   `json:"cards"`
}

Index is the on-disk shape of .focus/index.json.

func Load

func Load(focusDir string) (*Index, error)

Load reads .focus/index.json from a board's .focus/ directory. Returns os.ErrNotExist if no index has been written yet (first `focus new` is the typical writer); callers should treat that as an empty index, not a hard error.

func LoadOrEmpty

func LoadOrEmpty(focusDir string) (*Index, error)

LoadOrEmpty returns the existing index or, if none has been written, a fresh empty Index with NextID=1. Convenience for command code that needs to read-then-modify; the alternative is each handler open-coding the os.ErrNotExist check.

func (*Index) AllocateID

func (idx *Index) AllocateID() int

AllocateID returns the next available card id and increments NextID in place. The high-water-mark invariant (designs/focus-v2.md §"`next_id` allocation rule") is maintained by callers via Save.

func (*Index) Find

func (idx *Index) Find(id int) *Entry

Find returns the entry with the given id, or nil if not present.

func (*Index) MaxID

func (idx *Index) MaxID() int

MaxID returns the highest id present in the index, or 0 if empty. Used by Reindex to compute the next_id high-water mark.

func (*Index) Remove

func (idx *Index) Remove(id int) bool

Remove drops the entry with the given id from the index. It does NOT lower NextID — burned ids stay burned (designs/focus-v2.md §"`next_id` allocation rule"). Returns true if an entry was removed.

func (*Index) Upsert

func (idx *Index) Upsert(e Entry)

Upsert replaces the entry for e.ID if it exists, else appends it. Sorting is deferred to Save.

Jump to

Keyboard shortcuts

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