Documentation
¶
Index ¶
- Constants
- Variables
- func FormatOpenQuestionItem(item OpenQuestionItem, answer string, ending string) string
- func ParseFrontmatterMap(ctx context.Context, content []byte) (map[string]any, error)
- type Config
- type DailyNoteStorage
- type DecisionStorage
- type GoalStorage
- type ObjectiveStorage
- type OpenQuestionItem
- type PageStorage
- type Storage
- type TaskStorage
- type ThemeStorage
- type TopicStorage
- type VisionStorage
Constants ¶
const AnswerDelimiter = " → **"
AnswerDelimiter separates an item's question from its recorded answer. It is exported so a writer can refuse an answer containing it: an answer that carried the delimiter would make the line ambiguous, and re-answering would then split at the wrong place and destroy the previous answer.
Variables ¶
var ( // CheckboxRegex matches a Markdown checkbox line with either `-` or `*` as // the list marker. Capture groups: 1=leading whitespace, 2=state (` `, `x`, // or `/`), 3=task text. Shared across storage and ops packages to keep the // parser shape in one place. CheckboxRegex = regexp.MustCompile(`^(\s*)[-*] \[([ x/])\] (.+)$`) // CheckboxCompleteRegex matches an unchecked or in-progress checkbox marker // (` ` or `/`) and is used by rewriters that force a line to checked. // Capture groups: 1=list marker (`-` or `*`), 2=state (` ` or `/`). CheckboxCompleteRegex = regexp.MustCompile(`([-*]) \[([ /])\]`) // CheckboxUncompleteRegex matches a checked checkbox marker and is used by // rewriters that force a line to unchecked. Capture group 1=list marker. CheckboxUncompleteRegex = regexp.MustCompile(`([-*]) \[x\]`) )
var ErrNotFound = stderrors.New("file not found")
ErrNotFound indicates a requested markdown file could not be resolved by name within a vault. Callers (notably the multi-vault dispatcher) test for it with errors.Is to distinguish a genuine not-found from other failures (e.g. a precondition failure such as incomplete subtasks).
Functions ¶
func FormatOpenQuestionItem ¶ added in v0.163.0
func FormatOpenQuestionItem(item OpenQuestionItem, answer string, ending string) string
FormatOpenQuestionItem renders an item with the given answer, preserving the item's own list marker, indentation and line ending. answer must contain neither AnswerDelimiter nor `**` — the caller enforces both — which is what lets ParseOpenQuestions split the result back into the same question and answer. An answer carrying `**` would close the emphasis early and read back with extra asterisks: `**critical**` becomes `***critical**`.
func ParseFrontmatterMap ¶ added in v0.149.0
ParseFrontmatterMap parses the YAML frontmatter block from content into a map[string]any, preserving all fields including unknown ones. Returns an error if no frontmatter block is found or YAML is invalid. A bare Obsidian wikilink value is quoted before unmarshal — see quoteBareWikilinks — so it is read as a string rather than a nested list.
Types ¶
type Config ¶
type Config struct {
TasksDir string
GoalsDir string
ThemesDir string
ObjectivesDir string
VisionDir string
DailyDir string
TopicsDir string
Excludes []string
}
Config holds the configuration for storage paths.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns the default storage configuration.
func NewConfigFromVault ¶
NewConfigFromVault creates a Config from a Vault.
type DailyNoteStorage ¶ added in v0.25.3
type DailyNoteStorage interface {
ReadDailyNote(ctx context.Context, vaultPath string, date string) (string, error)
WriteDailyNote(ctx context.Context, vaultPath string, date string, content string) error
}
func NewDailyNoteStorage ¶ added in v0.25.3
func NewDailyNoteStorage(storageConfig *Config) DailyNoteStorage
NewDailyNoteStorage creates a storage for daily note operations only.
type DecisionStorage ¶ added in v0.25.3
type DecisionStorage interface {
ListDecisions(ctx context.Context, vaultPath string) ([]*domain.Decision, error)
FindDecisionByName(ctx context.Context, vaultPath string, name string) (*domain.Decision, error)
WriteDecision(ctx context.Context, decision *domain.Decision) error
}
func NewDecisionStorage ¶ added in v0.25.3
func NewDecisionStorage(storageConfig *Config) DecisionStorage
NewDecisionStorage creates a storage for decision operations only.
type GoalStorage ¶ added in v0.25.3
type GoalStorage interface {
WriteGoal(ctx context.Context, goal *domain.Goal) error
FindGoalByName(ctx context.Context, vaultPath string, name string) (*domain.Goal, error)
}
func NewGoalStorage ¶ added in v0.25.3
func NewGoalStorage(storageConfig *Config) GoalStorage
NewGoalStorage creates a storage for goal operations only.
type ObjectiveStorage ¶ added in v0.29.0
type ObjectiveStorage interface {
WriteObjective(ctx context.Context, objective *domain.Objective) error
FindObjectiveByName(
ctx context.Context,
vaultPath string,
name string,
) (*domain.Objective, error)
}
func NewObjectiveStorage ¶ added in v0.29.0
func NewObjectiveStorage(storageConfig *Config) ObjectiveStorage
NewObjectiveStorage creates a storage for objective operations only.
type OpenQuestionItem ¶ added in v0.163.0
OpenQuestionItem is one item of a task's `Open Questions` section.
Index is POSITIONAL — the item's ordinal among the section's items, counted from 1 — and not the numeric list marker the file happens to render. A section written as `1.` / `3.` reports indices 1 and 2. Callers address items by this index; the marker is preserved on write but never interpreted.
Question and Answer are the item's text split at its trailing ` → **<answer>**` marker, which is the form this package's writer produces. Splitting here, once, is what keeps the reader and any rewriter agreeing on what "the question" is — a rewriter that re-derived the split could disagree and edit the wrong text. Answer is empty for an item that carries none.
Line is the item's index into strings.Split(content, "\n") and Marker is its list prefix (indentation, list marker and the whitespace after it), so a rewriter can address the same physical line the reader counted and preserve the file's own list style.
func ParseOpenQuestions ¶ added in v0.163.0
func ParseOpenQuestions(ctx context.Context, content string) ([]OpenQuestionItem, error)
ParseOpenQuestions returns the top-level list items of the first `Open Questions` section in content, in section order, each carrying its 1-based index and the line it occupies. A content without such a section yields an empty (non-nil) slice, so a caller can serialize it as `[]` rather than `null`. A blank list item is skipped rather than yielding an empty question, and the index counts only the items returned.
The heading is matched EXACTLY and case-sensitively against `Open Questions` at any level. A variant such as `Open questions` or `Open Questions:` is not recognised, and the section then reads as absent — an empty list with no error, which is the documented contract in docs/task-writing.md.
This is the single parse both the reader and any rewriter use, so the index a caller names always addresses the line the rewriter edits and both agree on where the question ends and the answer begins.
type PageStorage ¶ added in v0.25.3
type PageStorage interface {
ListPages(ctx context.Context, vaultPath string, pagesDir string) ([]*domain.Page, error)
// ReadPage returns a single page from a specific directory in the vault.
// Unlike ListPages it reads only the named file, and it fails when that file
// is missing or unparseable rather than skipping it.
//
// name must be a bare page base name without the .md extension — the same
// value ListPages reports in Page.Name.
ReadPage(
ctx context.Context,
vaultPath string,
pagesDir string,
name string,
) (*domain.Page, error)
}
func NewPageStorage ¶ added in v0.25.3
func NewPageStorage(storageConfig *Config) PageStorage
NewPageStorage creates a storage for page operations only.
type Storage ¶
type Storage interface {
TaskStorage
GoalStorage
ThemeStorage
ObjectiveStorage
VisionStorage
TopicStorage
DailyNoteStorage
PageStorage
DecisionStorage
// Legacy methods — used by storage tests, not by ops.
// Keep on composed interface for backward compat; not on narrow interfaces.
ReadTask(ctx context.Context, vaultPath string, taskID domain.TaskID) (*domain.Task, error)
ListTasks(ctx context.Context, vaultPath string) ([]*domain.Task, error)
ReadGoal(ctx context.Context, vaultPath string, goalID domain.GoalID) (*domain.Goal, error)
ReadTheme(ctx context.Context, vaultPath string, themeID domain.ThemeID) (*domain.Theme, error)
ReadObjective(
ctx context.Context,
vaultPath string,
objectiveID domain.ObjectiveID,
) (*domain.Objective, error)
ReadVision(
ctx context.Context,
vaultPath string,
visionID domain.VisionID,
) (*domain.Vision, error)
}
func NewStorage ¶
NewStorage creates a new markdown storage instance with custom configuration.
type TaskStorage ¶ added in v0.25.3
type TaskStorage interface {
WriteTask(ctx context.Context, task *domain.Task) error
FindTaskByName(ctx context.Context, vaultPath string, name string) (*domain.Task, error)
// ListTasks returns every task in the vault's configured tasks_dir. An
// unreadable task file is skipped (logged at debug level) so a listing still
// succeeds — see ListTasksStrict for the caller that must not lose a file.
ListTasks(ctx context.Context, vaultPath string) ([]*domain.Task, error)
// ListTasksStrict returns every task in the vault's configured tasks_dir and
// fails on an unreadable task file instead of skipping it. A caller whose
// result must not silently describe a smaller set (the weekly rollup) uses
// this; the error names the offending file.
ListTasksStrict(ctx context.Context, vaultPath string) ([]*domain.Task, error)
}
func NewTaskStorage ¶ added in v0.25.3
func NewTaskStorage(storageConfig *Config) TaskStorage
NewTaskStorage creates a storage for task operations only.
type ThemeStorage ¶ added in v0.29.0
type ThemeStorage interface {
WriteTheme(ctx context.Context, theme *domain.Theme) error
FindThemeByName(ctx context.Context, vaultPath string, name string) (*domain.Theme, error)
}
func NewThemeStorage ¶ added in v0.29.0
func NewThemeStorage(storageConfig *Config) ThemeStorage
NewThemeStorage creates a storage for theme operations only.
type TopicStorage ¶ added in v0.142.0
type TopicStorage interface {
WriteTopic(ctx context.Context, topic *domain.Topic) error
FindTopicByName(ctx context.Context, vaultPath string, name string) (*domain.Topic, error)
}
func NewTopicStorage ¶ added in v0.142.0
func NewTopicStorage(storageConfig *Config) TopicStorage
NewTopicStorage creates a storage for topic operations only.
type VisionStorage ¶ added in v0.29.0
type VisionStorage interface {
WriteVision(ctx context.Context, vision *domain.Vision) error
FindVisionByName(ctx context.Context, vaultPath string, name string) (*domain.Vision, error)
}
func NewVisionStorage ¶ added in v0.29.0
func NewVisionStorage(storageConfig *Config) VisionStorage
NewVisionStorage creates a storage for vision operations only.