Documentation
¶
Overview ¶
Package vault is the filesystem engine behind every zn command and the terminal UI: it reads and writes a ZenNotes vault exactly the way the desktop app, the bundled `zn`, and the self-hosted server do.
SYNCED SEMANTICS. The parsers in this package (tags, wikilinks, excerpts, task lines, frontmatter, system folder paths) are deliberate copies of the ones in the ZenNotes repo: `apps/desktop/src/mcp/vault-ops.ts`, `packages/shared-domain/src/*.ts` and `apps/server/internal/vault/*.go`. A note must read the same everywhere, so a change to one of those has to land here too, byte for byte where the rules are byte rules.
Index ¶
- Constants
- Variables
- func AnchorForText(doc, anchorText string) (start, end int, text string, err error)
- func AppendToBody(body, text string) string
- func BodyHasLocalAsset(body string) bool
- func BucketTasksByDueDate(tasks []Task) map[string][]Task
- func BuildExcerpt(body string) string
- func BuildOpenNoteDeepLink(relPath string) string
- func ComposeTaskFile(in ComposeTaskFileInput) string
- func ExtractOpenTaskBlocks(markdown string) (moved []string, rest string)
- func ExtractTags(body string) []string
- func ExtractWikilinks(body string) []string
- func FolderSubpathOf(rel string, folder NoteFolder, primaryAtRoot bool, paths map[string]string) string
- func ForwardTaskLines(markdown string, taskIndex int, linkToken string) (body string, moved []string)
- func ForwardTaskSubtree(markdown string, taskIndex int, linkToken string) (body string, childLines []string)
- func Frontmatter(body string) (block string, rest string, ok bool)
- func InsertAtLineInBody(body string, lineNumber int, text string) string
- func InsertTasksUnderTasksHeading(body string, taskLines []string) string
- func IsAtomicWriteTempPath(p string) bool
- func IsObsidianExcalidrawMarkdown(content string) bool
- func IsObsidianExcalidrawPath(p string) bool
- func IsOverdue(t Task, today time.Time) bool
- func IsPathExcludedFromTasks(relPath string, excluded []string) bool
- func IsTaskOpen(t Task) bool
- func IsTypstPreamblePath(relPath, folder string) bool
- func IsValidFolder(f NoteFolder) bool
- func IsValidISODate(s string) bool
- func LineOfOffset(doc string, units int) int
- func MoveTaskLine(markdown string, fromTaskIndex, targetTaskIndex int, before bool) string
- func NewCommentID() string
- func NormalizeCommentAuthor(value string) string
- func NormalizePriority(raw string) string
- func NormalizeRelPath(rel string) string
- func NormalizeSystemFolderPaths(raw map[string]string) map[string]string
- func NormalizeTasksExcludedFolders(values []string) []string
- func NoteTasksMode(val string) string
- func ParseFrontmatterFields(block string) map[string][]string
- func ParseFrontmatterScalars(raw string) (data map[string]string, body string)
- func ParseTaskIndex(taskID, indexStr string) (int, error)
- func PrependToBody(body, text string) string
- func RemoveTaskLine(markdown string, taskIndex int) (line string, body string, ok bool)
- func ReplaceInBody(body, find, replace string, all bool) (string, int, error)
- func ResolveCommentAnchor(c NoteComment, doc string) (from, to int)
- func ResolveFolderPath(folder NoteFolder, paths map[string]string) string
- func RetitleLeadingHeading(body, title string) string
- func RewriteWikilinksForRename(body string, notes []NoteMeta, oldPath, newTitle string) (string, int)
- func SafeJoin(root, rel string) (string, error)
- func SafeTemplateSlug(slug string) string
- func SanitizeTitle(raw string) string
- func SetTaskCancelled(markdown string, taskIndex int, cancelled bool) string
- func SetTaskChecked(markdown string, taskIndex int, checked bool) string
- func SetTaskDue(markdown string, taskIndex int, due string) string
- func SetTaskField(markdown string, taskIndex int, key, value string) string
- func SetTaskFileCancelled(body string, cancelled bool) string
- func SetTaskFileField(body, key, value string) string
- func SetTaskFileInProgress(body string, inProgress bool) string
- func SetTaskFileStatus(body string, done bool, now time.Time) string
- func SetTaskInProgress(markdown string, taskIndex int, inProgress bool) string
- func SetTaskPriority(markdown string, taskIndex int, priority string) string
- func SetTaskText(markdown string, taskIndex int, text string) string
- func SetTaskWaiting(markdown string, taskIndex int, waiting bool) string
- func SplitTaskID(taskID string) (rel string, indexStr string, err error)
- func SplitWikilinkContent(content string) (target, anchor, alias string)
- func StrPtr(s string) *string
- func StripCodeContent(body string) string
- func TaskFilePriorityValue(priority string) string
- func ToPosix(p string) string
- func TodayISO(now time.Time) string
- func ToggleFileTaskInBody(body string, currentlyChecked bool, now time.Time) string
- func ToggleTaskInBody(body string, targetIndex int, dialect TaskDialect) (next string, ok bool)
- func UTF16Length(s string) int
- func Unquote(v string) string
- func UpdateFrontmatterFields(body string, updates []FrontmatterUpdate) string
- func YAMLValue(value string) string
- type AssetMeta
- type ComposeTaskFileInput
- type CustomTemplateFile
- type DateNotePattern
- type FolderEntry
- type FrontmatterUpdate
- type NoteComment
- type NoteCommentThread
- type NoteContent
- type NoteFolder
- type NoteMeta
- type OutlineItem
- type ParseTasksOptions
- type PeriodicNotes
- type PrimaryNotesLocation
- type Task
- type TaskDialect
- type TaskGroups
- type TextSearchMatch
- type Vault
- func (v *Vault) AbsPath(rel string) (string, error)
- func (v *Vault) AppendToNote(rel, text string) (NoteMeta, error)
- func (v *Vault) ArchiveNote(rel string) (NoteMeta, error)
- func (v *Vault) Backlinks(rel string) ([]NoteMeta, error)
- func (v *Vault) CreateFolder(folder NoteFolder, subpath string) error
- func (v *Vault) CreateNote(folder NoteFolder, title, subpath string, body *string) (NoteMeta, error)
- func (v *Vault) DeleteFolder(folder NoteFolder, subpath string) error
- func (v *Vault) DeleteNote(rel string) error
- func (v *Vault) DeleteTemplate(sourcePath string) error
- func (v *Vault) DuplicateNote(rel string) (NoteMeta, error)
- func (v *Vault) EmptyTrash() error
- func (v *Vault) FolderDirName(folder NoteFolder) string
- func (v *Vault) FolderOf(rel string) (NoteFolder, bool)
- func (v *Vault) FolderRoot(folder NoteFolder) string
- func (v *Vault) Info() VaultInfo
- func (v *Vault) InsertAtLine(rel string, lineNumber int, text string) (NoteMeta, error)
- func (v *Vault) ListAssets() ([]AssetMeta, error)
- func (v *Vault) ListCSVFiles() ([]string, error)
- func (v *Vault) ListDatabaseDirs() ([]FolderEntry, error)
- func (v *Vault) ListFolders() ([]FolderEntry, error)
- func (v *Vault) ListNotes() ([]NoteMeta, error)
- func (v *Vault) ListTemplates() ([]CustomTemplateFile, error)
- func (v *Vault) MetaFor(rel string) (NoteMeta, error)
- func (v *Vault) MoveNote(rel string, target NoteFolder, targetSubpath string) (NoteMeta, error)
- func (v *Vault) MoveToTrash(rel string) (NoteMeta, error)
- func (v *Vault) PrependToNote(rel, text string) (NoteMeta, error)
- func (v *Vault) PrimaryAtRoot() bool
- func (v *Vault) PrimaryNotesLocation() PrimaryNotesLocation
- func (v *Vault) ReadFileTextOrNull(rel string) (*string, error)
- func (v *Vault) ReadNote(rel string) (NoteContent, error)
- func (v *Vault) ReadNoteComments(rel string) ([]NoteComment, error)
- func (v *Vault) ReadTemplate(sourcePath string) (string, error)
- func (v *Vault) RelDirFor(folder NoteFolder, subpath string) string
- func (v *Vault) RenameFile(oldRel, newRel string) error
- func (v *Vault) RenameFolder(folder NoteFolder, oldSubpath, newSubpath string) (string, error)
- func (v *Vault) RenameNote(rel, nextTitle string) (NoteMeta, error)
- func (v *Vault) ReplaceInNote(rel, find, replace string, all bool) (NoteMeta, int, error)
- func (v *Vault) RestoreFromTrash(rel string) (NoteMeta, error)
- func (v *Vault) Root() string
- func (v *Vault) ScanTasks(opts ParseTasksOptions) ([]Task, error)
- func (v *Vault) ScanTasksForPath(rel string, opts ParseTasksOptions) ([]Task, error)
- func (v *Vault) SearchText(query string, limit int) ([]TextSearchMatch, error)
- func (v *Vault) Settings() VaultSettings
- func (v *Vault) SubpathOf(rel string) string
- func (v *Vault) SwitchPrimaryMode(target PrimaryNotesLocation) ([]string, error)
- func (v *Vault) ToggleTask(taskID string, dialect TaskDialect) (*Task, error)
- func (v *Vault) UnarchiveNote(rel string) (NoteMeta, error)
- func (v *Vault) UpdateSettings(patch func(raw map[string]any)) error
- func (v *Vault) WriteFileText(rel, text string) error
- func (v *Vault) WriteNote(rel, body string) (NoteMeta, error)
- func (v *Vault) WriteNoteComments(rel string, comments []NoteComment) ([]NoteComment, error)
- func (v *Vault) WriteTemplate(input WriteTemplateInput) (CustomTemplateFile, error)
- type VaultInfo
- type VaultSettings
- type WriteTemplateInput
Constants ¶
const ( NoteCommentsDir = "comments" NoteCommentsSuffix = ".comments.json" MaxCommentAnchorTextLength = 500 MaxCommentAuthorLength = 80 )
const ( AssetsDir = "assets" PrimaryAttachmentsDir = "attachements" // intentional legacy spelling, never "fix" it InternalVaultDir = ".zennotes" DefaultDailyNotesDirectory = "Daily Notes" DefaultDailyNoteTitlePattern = "yyyy-MM-dd" DefaultWeeklyNotesDirectory = "Weekly Notes" DefaultWeeklyNoteTitlePattern = "yyyy-'W'ww" DefaultMonthlyNotesDirectory = "Monthly Notes" DefaultMonthlyNoteTitlePattern = "yyyy-MM" DefaultDateNoteLocale = "system" DefaultTypstPreambleFolder = "typst" )
const DeepLinkScheme = "zennotes"
DeepLinkScheme is the URL scheme the desktop app registers.
const TaskFileTag = "task"
TaskFileTag is the frontmatter tag that marks a whole note as a task.
Variables ¶
var AllFolders = []NoteFolder{FolderInbox, FolderQuick, FolderArchive, FolderTrash}
AllFolders lists the buckets in the order every listing walks them.
var ErrAnchorNotFound = errors.New("anchor_text was not found in the note. Pass the text exactly as it appears (read_note shows it), or omit it for a note-level comment.")
ErrAnchorNotFound says anchor text is not in the note.
var ErrInvalidTemplate = errors.New("invalid template request")
ErrInvalidTemplate marks a template path outside the templates directory.
var ErrPathEscape = errors.New("path escapes vault")
ErrPathEscape is returned for a vault-relative path that resolves outside the vault root, through `..` or a symbolic link.
var ErrTaskGone = errors.New("task no longer exists at that location")
ErrTaskGone says a task id no longer names a task in its note.
var LiveFolders = []NoteFolder{FolderInbox, FolderQuick, FolderArchive}
LiveFolders are the buckets searches and task scans cover: everything but the trash.
Functions ¶
func AnchorForText ¶
AnchorForText places a new comment: an exact match of anchorText first, then one ignoring case; empty text means a note-level comment at the top.
func AppendToBody ¶
AppendToBody is the body with text added after a blank line.
func BodyHasLocalAsset ¶
BodyHasLocalAsset reports whether the note embeds or links a local attachment (an image, a PDF, audio or video).
func BucketTasksByDueDate ¶
BucketTasksByDueDate groups open tasks by due date; undated ones land under "unscheduled". An undated forwarded record is a record of a move, not unscheduled work, and is skipped.
func BuildExcerpt ¶
BuildExcerpt makes a short plaintext preview from markdown: no frontmatter, no code, links reduced to their text, markup stripped, whitespace collapsed, capped at 220 characters.
func BuildOpenNoteDeepLink ¶
BuildOpenNoteDeepLink is the shareable URL that opens a vault-relative note in the app. Segments are percent-encoded the way encodeURIComponent does it, with parentheses encoded as well because these URLs live inside markdown `[title](url)` links, where a bare `)` ends the link.
func ComposeTaskFile ¶
func ComposeTaskFile(in ComposeTaskFileInput) string
ComposeTaskFile builds a task-file note in the TaskNotes shape.
func ExtractOpenTaskBlocks ¶
ExtractOpenTaskBlocks pulls every open task line (`[ ]` and `[/]`) with its indented children out of markdown, for rolling unfinished work forward into today's daily note.
func ExtractTags ¶
ExtractTags returns the unique tags of a note: frontmatter `tags` (a bare scalar splits on commas and whitespace) plus inline `#tags` outside code.
func ExtractWikilinks ¶
ExtractWikilinks returns unique [[wikilink]] targets outside code, embeds included, exactly as the desktop CLI reports them.
func FolderSubpathOf ¶
func FolderSubpathOf(rel string, folder NoteFolder, primaryAtRoot bool, paths map[string]string) string
FolderSubpathOf is the note's directory relative to its bucket root, or "" at the bucket root. `inbox/Work/Note.md` gives `Work`; in root primary mode `Work/Note.md` gives `Work`.
func ForwardTaskLines ¶
func ForwardTaskLines(markdown string, taskIndex int, linkToken string) (body string, moved []string)
ForwardTaskLines is ForwardTaskSubtree plus what the destination note receives: the task itself as a copy with its indent dropped and no link, then its subtree. A task without subtasks still yields its own line, so forwarding never leaves a `[>]` record with nothing on the other side.
func ForwardTaskSubtree ¶
func ForwardTaskSubtree(markdown string, taskIndex int, linkToken string) (body string, childLines []string)
ForwardTaskSubtree flips the task at taskIndex to `[>]`, appends linkToken to it, and flips its open subtasks to `[>]` too. childLines is the subtree as it read before the flip, re-based to the parent's indent, so the caller can place it under a copy in the destination note.
func Frontmatter ¶
Frontmatter splits a leading `---` block off the body. ok is false when there is none; block is the text between the fences.
func InsertAtLineInBody ¶
InsertAtLineInBody inserts text before the zero-based lineNumber, clamped to the body.
func InsertTasksUnderTasksHeading ¶
InsertTasksUnderTasksHeading places task lines at the end of a `# Tasks` section when the note has one (before the next heading of the same or a higher level, or a horizontal rule), else appends them to the note.
func IsAtomicWriteTempPath ¶
IsAtomicWriteTempPath reports whether p is one of those scratch files.
func IsObsidianExcalidrawMarkdown ¶
IsObsidianExcalidrawMarkdown is true when the frontmatter carries Obsidian's `excalidraw-plugin` marker.
func IsObsidianExcalidrawPath ¶
IsObsidianExcalidrawPath is true for `*.excalidraw.md` drawings.
func IsPathExcludedFromTasks ¶
IsPathExcludedFromTasks reports whether a vault-relative POSIX path lives inside any excluded folder (segment-prefix match, case-sensitive).
func IsTaskOpen ¶
IsTaskOpen is true for a task that is neither done nor cancelled.
func IsTypstPreamblePath ¶
IsTypstPreamblePath reports whether a note sits in a directory named like the preamble folder, at any depth. Such notes hold Typst source and are left out of the tag index.
func IsValidFolder ¶
func IsValidFolder(f NoteFolder) bool
IsValidFolder reports whether f names one of the four buckets.
func IsValidISODate ¶
IsValidISODate accepts `YYYY-MM-DD` that names a real day.
func LineOfOffset ¶
LineOfOffset is the 1-based line of a UTF-16 offset in doc.
func MoveTaskLine ¶
MoveTaskLine relocates the task line at fromTaskIndex before or after the task line at targetTaskIndex.
func NormalizeCommentAuthor ¶
NormalizeCommentAuthor squeezes whitespace and caps the length.
func NormalizePriority ¶
NormalizePriority maps every accepted spelling onto high, med or low.
func NormalizeRelPath ¶
NormalizeRelPath turns `./inbox/Note.md` or `\inbox\Note.md` into `inbox/Note.md`, the form every listing reports.
func NormalizeSystemFolderPaths ¶
NormalizeSystemFolderPaths validates a raw systemFolderPaths map the way every other runtime does: single directory names, no reserved names, no folder claiming another folder's default name, no two folders resolving to the same directory. Nil when nothing survives.
func NormalizeTasksExcludedFolders ¶
NormalizeTasksExcludedFolders drops invalid entries and duplicates.
func NoteTasksMode ¶
NoteTasksMode reads the frontmatter `tasks:` value.
func ParseFrontmatterFields ¶
ParseFrontmatterFields parses a frontmatter block into flat fields: scalars, inline arrays (`tags: [a, b]`) and block lists (`tags:` then indented `- a`). Keys are lower-cased; every value is a slice (a scalar is a single-element slice). Best-effort, never fails.
func ParseFrontmatterScalars ¶
ParseFrontmatterScalars is the template/record-page reader: flat `key: value` lines only, quotes stripped, keys kept as written.
func ParseTaskIndex ¶
ParseTaskIndex validates the `#<n>` half of a task id.
func PrependToBody ¶
PrependToBody is the body with text inserted at the top, below any frontmatter.
func RemoveTaskLine ¶
RemoveTaskLine deletes the task line at taskIndex, returning it too.
func ReplaceInBody ¶
ReplaceInBody is a literal find-and-replace; all replaces every occurrence, otherwise only the first.
func ResolveCommentAnchor ¶
func ResolveCommentAnchor(c NoteComment, doc string) (from, to int)
ResolveCommentAnchor is where a comment's anchor sits in doc now: the stored offsets when the text there still matches, else the first occurrence of the anchored text, else the clamped stored offsets. The result is in UTF-16 units like the stored anchor.
func ResolveFolderPath ¶
func ResolveFolderPath(folder NoteFolder, paths map[string]string) string
ResolveFolderPath is the on-disk directory name of a system folder.
func RetitleLeadingHeading ¶
RetitleLeadingHeading rewrites the note's leading `# Heading` to title, skipping frontmatter and blank lines. A note whose first line is anything but an H1 is returned unchanged: the heading is never invented.
func RewriteWikilinksForRename ¶
func RewriteWikilinksForRename(body string, notes []NoteMeta, oldPath, newTitle string) (string, int)
RewriteWikilinksForRename rewrites every `[[target]]` / `![[target]]` in body whose target resolves to the note at oldPath, pointing it at newTitle. Aliases, anchors and embeds are preserved; code is skipped. notes must reflect the vault BEFORE the rename.
func SafeJoin ¶
SafeJoin cleans a user-supplied relative POSIX path and joins it onto root, refusing anything that resolves outside root. Existing symlinked components must still resolve inside root; components that do not exist yet are left alone (they cannot be links until they are created).
func SafeTemplateSlug ¶
SafeTemplateSlug keeps lowercase letters, digits and dashes; every run of anything else becomes one dash, and leading and trailing dashes go.
func SanitizeTitle ¶
SanitizeTitle makes a title safe as a filename on every platform.
func SetTaskCancelled ¶
SetTaskCancelled marks the line `[-]`, or back to `[ ]`.
func SetTaskChecked ¶
SetTaskChecked is the editor's toggle: unchecking an in-progress `[/]` keeps the `/`, since it already is not done.
func SetTaskDue ¶
SetTaskDue replaces, inserts or removes the `due:YYYY-MM-DD` token.
func SetTaskField ¶
SetTaskField replaces, inserts or removes an inline `@key:value` token.
func SetTaskFileCancelled ¶
SetTaskFileCancelled writes `status: cancelled`, or back to `open`.
func SetTaskFileField ¶
SetTaskFileField sets any frontmatter scalar (`due`, `priority` in TaskNotes vocabulary, `status`); an empty value removes the key.
func SetTaskFileInProgress ¶
SetTaskFileInProgress writes `status: in-progress`, or back to `open`.
func SetTaskFileStatus ¶
SetTaskFileStatus writes `status: done` plus `completedDate` when checking, and back to `open` (clearing `completedDate`) when unchecking.
func SetTaskInProgress ¶
SetTaskInProgress marks the line `[/]`, or back to `[ ]`.
func SetTaskPriority ¶
SetTaskPriority replaces, inserts or removes the `!priority` token.
func SetTaskText ¶
SetTaskText replaces everything after the checkbox.
func SetTaskWaiting ¶
SetTaskWaiting adds or removes the `@waiting` marker.
func SplitTaskID ¶
SplitTaskID splits `<path>#<index>` into its halves; indexStr is the literal `task` for a whole-note task.
func SplitWikilinkContent ¶
SplitWikilinkContent separates `Target#anchor|alias` into its parts; the anchor keeps its leading `#` or `^` and the alias its leading `|`.
func StripCodeContent ¶
StripCodeContent blanks fenced and inline code so the tag, link and excerpt scanners never read code as content. Line-based and indentation-tolerant: a fence nested under a list item is still a code block.
func TaskFilePriorityValue ¶
TaskFilePriorityValue maps a ZenNotes priority onto TaskNotes' vocabulary.
func ToggleFileTaskInBody ¶
ToggleFileTaskInBody flips a task file's frontmatter `status` (and its `completedDate`).
func ToggleTaskInBody ¶
func ToggleTaskInBody(body string, targetIndex int, dialect TaskDialect) (next string, ok bool)
ToggleTaskInBody flips the nth checkbox the way `zn task toggle` and the MCP tool do: open and done flip, an in-progress `[/]` checks off, and the forwarded and cancelled record markers are left alone. ok is false when the body holds no task at that index.
func UpdateFrontmatterFields ¶
func UpdateFrontmatterFields(body string, updates []FrontmatterUpdate) string
UpdateFrontmatterFields sets (or, with a nil value, removes) scalar frontmatter fields, preserving key order and every other line. Creates the block when the note has none. Keys match case-insensitively but are written with the casing given.
Types ¶
type AssetMeta ¶
type AssetMeta struct {
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
UpdatedAt int64 `json:"updatedAt"`
}
AssetMeta describes a file under the vault's attachment directories.
type ComposeTaskFileInput ¶
type ComposeTaskFileInput struct {
Title string
Status string
Priority string
Due string
Scheduled string
Tags []string
DateCreated string
Body string
}
ComposeTaskFileInput describes a new whole-note task.
type CustomTemplateFile ¶
CustomTemplateFile is a raw custom template as it lives on disk.
type DateNotePattern ¶
type DateNotePattern struct {
Directory string `json:"directory"`
TitlePattern string `json:"titlePattern,omitempty"`
Locale string `json:"locale,omitempty"`
}
DateNotePattern is one (directory, title pattern, locale) triple a periodic-note kind has used; the current one plus any legacy ones.
type FolderEntry ¶
type FolderEntry struct {
Folder NoteFolder `json:"folder"`
Subpath string `json:"subpath"`
}
FolderEntry is one subfolder under a bucket, as `zn folder list` reports it.
type FrontmatterUpdate ¶
FrontmatterUpdate is one field to set (Value non-nil) or remove (nil).
type NoteComment ¶
type NoteComment struct {
ID string `json:"id"`
NotePath string `json:"notePath"`
AnchorStart int `json:"anchorStart"`
AnchorEnd int `json:"anchorEnd"`
AnchorText string `json:"anchorText"`
Body string `json:"body"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
ResolvedAt *int64 `json:"resolvedAt"`
Author string `json:"author,omitempty"`
ParentID string `json:"parentId,omitempty"`
}
NoteComment is one stored comment or reply.
func NormalizeNoteComment ¶
func NormalizeNoteComment(input NoteComment, notePath string, now int64) (NoteComment, bool)
NormalizeNoteComment validates one record; a comment with no body is dropped (ok false), everything else is coerced into shape.
func NormalizeNoteComments ¶
func NormalizeNoteComments(raw []NoteComment, notePath string, now int64) []NoteComment
NormalizeNoteComments validates a whole list: drops malformed and duplicate records, keeps creation order, and turns a reply whose parent is missing into a comment of its own rather than losing it.
func ThreadRootOf ¶
func ThreadRootOf(comments []NoteComment, id string) (NoteComment, bool)
ThreadRootOf is the top-level comment an id belongs to, or ok false.
type NoteCommentThread ¶
type NoteCommentThread struct {
Comment NoteComment
Replies []NoteComment
}
NoteCommentThread is a top-level comment with its replies in order.
func ThreadNoteComments ¶
func ThreadNoteComments(comments []NoteComment) []NoteCommentThread
ThreadNoteComments groups comments into threads. A reply to a reply lands in the same thread, so a thread stays one level deep.
type NoteContent ¶
NoteContent is a note with its body.
type NoteFolder ¶
type NoteFolder string
NoteFolder is one of the four conceptual top-level buckets. Their on-disk directory names can be remapped per vault (`systemFolderPaths` in vault.json), so a NoteFolder is never joined onto a path directly; see (*Vault).folderRoot.
const ( FolderInbox NoteFolder = "inbox" FolderQuick NoteFolder = "quick" FolderArchive NoteFolder = "archive" FolderTrash NoteFolder = "trash" )
func FolderForRelativePath ¶
func FolderForRelativePath(rel string, paths map[string]string) (NoteFolder, bool)
FolderForRelativePath classifies a vault-relative path by its first segment. Root-level files belong to inbox (the root primary layout); hidden names and dotfiles are not notes.
func SystemFolderForDirName ¶
func SystemFolderForDirName(name string, paths map[string]string) (NoteFolder, bool)
SystemFolderForDirName classifies a top-level directory name. Only the RESOLVED name of each folder counts, case-insensitively: with inbox remapped to `01 - Entry`, a directory literally named `inbox/` is an ordinary user folder.
type NoteMeta ¶
type NoteMeta struct {
// Path is vault-relative and always POSIX-separated.
Path string `json:"path"`
// Link is the `zennotes://open?path=…` URL that focuses the app on the
// note. Presented to humans; tools are handed Path.
Link string `json:"link"`
Title string `json:"title"`
Folder NoteFolder `json:"folder"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
Size int64 `json:"size"`
Tags []string `json:"tags"`
Wikilinks []string `json:"wikilinks"`
Excerpt string `json:"excerpt"`
}
NoteMeta is what `zn list --json` prints for a note. Field names and order match the desktop CLI so scripts reading its JSON keep working.
func BacklinksIn ¶
BacklinksIn lists which of notes wikilink to the note at relPath, matching on title and never counting the note itself. Pure, so the remote backend gets the same answer from a listing it fetched.
type OutlineItem ¶
OutlineItem is one heading of a note.
func Outline ¶
func Outline(body string) []OutlineItem
Outline lists the ATX and setext headings of a note, skipping a leading frontmatter block and anything inside fenced code. Lines are 1-based.
type ParseTasksOptions ¶
type ParseTasksOptions struct {
// IncludeExcluded scans past the vault's excluded-folders list and the
// note-level frontmatter `tasks:` opt-out. The `--include-excluded`
// escape hatch; listings never set it on their own.
IncludeExcluded bool
Dialect TaskDialect
}
ParseTasksOptions controls scanning past the exclusions and the grammar.
type PeriodicNotes ¶
type PeriodicNotes struct {
Enabled bool
Directory string
TitlePattern string
Locale string
LegacyPatterns []DateNotePattern
TemplateID string
// Daily only.
TasksDueOnNoteDate bool
RolloverUnfinishedTasks bool
}
PeriodicNotes are the daily, weekly or monthly note settings.
type PrimaryNotesLocation ¶
type PrimaryNotesLocation string
PrimaryNotesLocation says where the inbox bucket lives: under `inbox/` (the classic layout) or directly at the vault root (Obsidian-style).
const ( PrimaryNotesInbox PrimaryNotesLocation = "inbox" PrimaryNotesRoot PrimaryNotesLocation = "root" )
type Task ¶
type Task struct {
// ID is `<path>#<taskIndex>` for a checkbox line and `<path>#task` for a
// task file. Stable across plain edits, so it is what toggles take.
ID string `json:"id"`
SourcePath string `json:"sourcePath"`
Link string `json:"link"`
NoteTitle string `json:"noteTitle"`
NoteFolder NoteFolder `json:"noteFolder"`
// LineNumber is zero-based over the whole file, frontmatter included.
LineNumber int `json:"lineNumber"`
TaskIndex int `json:"taskIndex"`
RawText string `json:"rawText"`
Content string `json:"content"`
Checked bool `json:"checked"`
// Cancelled is a `[-]` line: intentionally abandoned.
Cancelled bool `json:"cancelled"`
// InProgress is a `[/]` line: started, not finished. Still open work.
InProgress bool `json:"inProgress"`
// Forwarded is a `[>]` record: the task moved to another note.
Forwarded bool `json:"forwarded"`
Due string `json:"due,omitempty"`
Priority string `json:"priority,omitempty"`
Waiting bool `json:"waiting"`
// Fields holds inline `@key:value` tokens (lower-cased), the note's
// frontmatter `status:` folded in. Any key can drive a Kanban board.
Fields map[string]string `json:"fields,omitempty"`
Status string `json:"status,omitempty"`
Tags []string `json:"tags"`
// Kind is "file" for a whole-note task; empty means an inline checkbox.
Kind string `json:"kind,omitempty"`
Scheduled string `json:"scheduled,omitempty"`
CompletedDate string `json:"completedDate,omitempty"`
// DueInferred marks a due date derived from the containing daily note
// rather than written on the line. Set by the TUI, never by a scan.
DueInferred bool `json:"dueInferred,omitempty"`
}
Task is a checkbox line or a whole-note task file, with its inline metadata parsed out. Mirrors the desktop's VaultTask.
func FilterTasksForDisplay ¶
FilterTasksForDisplay drops tasks from archived notes unless showArchived.
func InferDailyTaskDueDates ¶
InferDailyTaskDueDates gives undated tasks living in a daily note an implicit due date equal to that note's date. Forwarded records are exempt.
func ParseTasks ¶
func ParseTasks(path, title string, folder NoteFolder, body string, opts ParseTasksOptions) []Task
ParseTasks walks a markdown body and returns every task: the note's own task file first (when it is one), then each checkbox line outside fenced code, with its inline metadata parsed out. `tasks: false` in the frontmatter emits nothing, `tasks: note` keeps only the file task, unless opts asks to scan past the opt-out.
func (Task) MarshalJSON ¶
MarshalJSON keeps the desktop CLI's exact key set: a checkbox task carries `forwarded` (true or false), a task file never does.
type TaskDialect ¶
type TaskDialect int
TaskDialect picks which task-line grammar a scan uses. The desktop app and its CLI disagree on the edges (numbered-list and blockquoted checkboxes exist for the app only, and the CLI leaves `@key:value` fields in the content), and a task id is only stable within one grammar, so each surface keeps the grammar it always had.
const ( // DialectApp is the grammar of the app's Tasks views, which the terminal // UI shares so a toggle there edits the line the app would. DialectApp TaskDialect = iota // DialectCLI is the grammar of the desktop's `zn task` commands and MCP // tools, so scripts keep getting the ids they got before. DialectCLI )
type TaskGroups ¶
type TaskGroups struct {
Today []Task
Upcoming []Task
Waiting []Task
Done []Task
Forwarded []Task
Cancelled []Task
OverdueCount int
}
TaskGroups is the Tasks list's bucketing: Today (undated, due today, and overdue), Upcoming, Waiting, Done, Forwarded, Cancelled.
func GroupTasks ¶
func GroupTasks(tasks []Task, today time.Time) TaskGroups
GroupTasks buckets tasks for the list view. Waiting overrides everything but Done; tasks without a due date land in Today.
type TextSearchMatch ¶
type TextSearchMatch struct {
Path string `json:"path"`
Link string `json:"link"`
Title string `json:"title"`
Folder NoteFolder `json:"folder"`
LineNumber int `json:"lineNumber"`
LineText string `json:"lineText"`
}
TextSearchMatch is one matching line from a full-text search.
type Vault ¶
type Vault struct {
// SyncTitleHeading rewrites a note's leading `# Heading` on rename, the
// desktop's "Sync title heading on rename" preference. On by default.
SyncTitleHeading bool
// contains filtered or unexported fields
}
Vault is one vault root on disk. Mutating operations serialize through a mutex; reads run concurrently.
func (*Vault) AppendToNote ¶
AppendToNote adds text to the end of a note after a blank line.
func (*Vault) ArchiveNote ¶
ArchiveNote moves a note into the archive.
func (*Vault) CreateFolder ¶
func (v *Vault) CreateFolder(folder NoteFolder, subpath string) error
CreateFolder creates a subfolder under a bucket.
func (*Vault) CreateNote ¶
func (v *Vault) CreateNote(folder NoteFolder, title, subpath string, body *string) (NoteMeta, error)
CreateNote creates a note in a bucket (and subpath), picking a non-colliding filename. body defaults to `# <title>` plus a blank line.
func (*Vault) DeleteFolder ¶
func (v *Vault) DeleteFolder(folder NoteFolder, subpath string) error
DeleteFolder removes a subfolder and everything inside it.
func (*Vault) DeleteNote ¶
DeleteNote removes a note permanently; a missing file is not an error.
func (*Vault) DeleteTemplate ¶
DeleteTemplate removes a template; one already gone is a success.
func (*Vault) DuplicateNote ¶
DuplicateNote copies a note next to itself with a " copy" suffix.
func (*Vault) EmptyTrash ¶
EmptyTrash permanently deletes everything in the trash bucket.
func (*Vault) FolderDirName ¶
func (v *Vault) FolderDirName(folder NoteFolder) string
FolderDirName is a bucket's on-disk directory name; "" for the inbox in root primary mode.
func (*Vault) FolderOf ¶
func (v *Vault) FolderOf(rel string) (NoteFolder, bool)
FolderOf classifies a vault-relative path.
func (*Vault) FolderRoot ¶
func (v *Vault) FolderRoot(folder NoteFolder) string
FolderRoot is the absolute directory holding a bucket's notes.
func (*Vault) InsertAtLine ¶
InsertAtLine inserts text before a zero-based line number.
func (*Vault) ListAssets ¶
ListAssets lists every file under the attachment directories, newest first.
func (*Vault) ListCSVFiles ¶
ListCSVFiles finds every database CSV in the vault at any depth: loose `.csv` files, and the data.csv of `.base` folders wherever they sit, including places the bucket walk does not cover. Hidden directories are skipped and `.base` folders are not descended into.
func (*Vault) ListDatabaseDirs ¶
func (v *Vault) ListDatabaseDirs() ([]FolderEntry, error)
ListDatabaseDirs enumerates every `.base` database folder.
func (*Vault) ListFolders ¶
func (v *Vault) ListFolders() ([]FolderEntry, error)
ListFolders enumerates every subfolder under each bucket, database folders excluded.
func (*Vault) ListTemplates ¶
func (v *Vault) ListTemplates() ([]CustomTemplateFile, error)
ListTemplates returns every custom template with its raw bytes.
func (*Vault) MoveToTrash ¶
MoveToTrash soft-deletes a note, keeping its subfolder for a later restore.
func (*Vault) PrependToNote ¶
PrependToNote inserts text at the top, below any frontmatter.
func (*Vault) PrimaryAtRoot ¶
PrimaryAtRoot is true in the Obsidian-style layout.
func (*Vault) PrimaryNotesLocation ¶
func (v *Vault) PrimaryNotesLocation() PrimaryNotesLocation
PrimaryNotesLocation decides whether the inbox lives under `inbox/` or at the vault root. An explicit vault.json setting wins, as it does in the desktop app. Only an absent setting needs disk inference. Cached briefly: every operation consults it and a root directory scan is not free.
func (*Vault) ReadFileTextOrNull ¶
ReadFileTextOrNull is the raw text of any vault file, database internals included; absent is (nil, "", nil) and every other failure is an error.
func (*Vault) ReadNote ¶
func (v *Vault) ReadNote(rel string) (NoteContent, error)
ReadNote returns a note with its body.
func (*Vault) ReadNoteComments ¶
func (v *Vault) ReadNoteComments(rel string) ([]NoteComment, error)
ReadNoteComments loads a note's comments; a missing sidecar is empty.
func (*Vault) ReadTemplate ¶
ReadTemplate returns one template's raw bytes.
func (*Vault) RelDirFor ¶
func (v *Vault) RelDirFor(folder NoteFolder, subpath string) string
RelDirFor is the vault-relative directory for a (folder, subpath).
func (*Vault) RenameFile ¶
RenameFile moves one vault file to a new vault-relative path.
func (*Vault) RenameFolder ¶
func (v *Vault) RenameFolder(folder NoteFolder, oldSubpath, newSubpath string) (string, error)
RenameFolder renames or moves a subfolder within its bucket and returns the new subpath.
func (*Vault) RenameNote ¶
RenameNote renames a note in place (same directory). The leading heading follows when SyncTitleHeading is on, and every `[[wikilink]]` in the vault that resolved to the note is rewritten to the new name.
func (*Vault) ReplaceInNote ¶
ReplaceInNote is a literal find-and-replace; no match means no write.
func (*Vault) RestoreFromTrash ¶
RestoreFromTrash moves a trashed note back to the inbox.
func (*Vault) ScanTasks ¶
func (v *Vault) ScanTasks(opts ParseTasksOptions) ([]Task, error)
ScanTasks parses every task in every live note, honoring the vault's excluded folders and each note's `tasks:` opt-out unless asked not to.
func (*Vault) ScanTasksForPath ¶
func (v *Vault) ScanTasksForPath(rel string, opts ParseTasksOptions) ([]Task, error)
ScanTasksForPath parses one note's tasks. A trashed or unclassifiable note contributes nothing, and neither does one under an excluded folder unless opts asks for it.
func (*Vault) SearchText ¶
func (v *Vault) SearchText(query string, limit int) ([]TextSearchMatch, error)
SearchText is a case-insensitive substring search over every line of every live note, capped at limit matches.
func (*Vault) Settings ¶
func (v *Vault) Settings() VaultSettings
Settings reads vault.json, reparsing only when the file changed. A missing or unreadable file yields the defaults: every read path must keep working for a vault that has never been opened in the app.
func (*Vault) SwitchPrimaryMode ¶
func (v *Vault) SwitchPrimaryMode(target PrimaryNotesLocation) ([]string, error)
SwitchPrimaryMode moves a vault between the classic layout, where notes live under the inbox directory, and root mode, where they sit at the vault root with the other system folders beside them. Files move and the explicit `primaryNotesLocation` setting is written to match. Favorites that name moved notes are rewritten. It refuses to run when a move would overwrite something.
func (*Vault) ToggleTask ¶
func (v *Vault) ToggleTask(taskID string, dialect TaskDialect) (*Task, error)
ToggleTask flips the task named by a stable id, counted in the given grammar. Exclusion-blind on purpose: an explicit id is an explicit ask. Returns (nil, nil) when the id no longer matches a task.
func (*Vault) UnarchiveNote ¶
UnarchiveNote moves an archived note back to the inbox.
func (*Vault) UpdateSettings ¶
UpdateSettings applies patch to the raw vault.json object and writes it back, preserving keys this process does not model. Used for favorites and the tasks exclusion list.
func (*Vault) WriteFileText ¶
WriteFileText writes any vault file's text, creating parents.
func (*Vault) WriteNoteComments ¶
func (v *Vault) WriteNoteComments(rel string, comments []NoteComment) ([]NoteComment, error)
WriteNoteComments replaces a note's comments; an empty list removes the sidecar.
func (*Vault) WriteTemplate ¶
func (v *Vault) WriteTemplate(input WriteTemplateInput) (CustomTemplateFile, error)
WriteTemplate saves a template under a slug derived from the request and removes the file it replaces when an edit changed the slug.
type VaultSettings ¶
type VaultSettings struct {
// ExplicitPrimary is the file's own primaryNotesLocation, empty when the
// file says nothing. Only an absent value is inferred from the layout; see
// (*Vault).PrimaryNotesLocation.
ExplicitPrimary PrimaryNotesLocation
DailyNotes PeriodicNotes
WeeklyNotes PeriodicNotes
MonthlyNotes PeriodicNotes
Favorites []string
SystemFolderPaths map[string]string
// TasksExcludedFolders are vault-relative directory paths whose notes
// never feed the Tasks surfaces.
TasksExcludedFolders []string
TypstPreambleFolder string
// Raw is the decoded file, kept so a targeted write can preserve every
// key this process does not model.
Raw map[string]any
}
VaultSettings is the parsed, normalized `.zennotes/vault.json`.
func ParseSettings ¶
func ParseSettings(raw map[string]any) VaultSettings
ParseSettings normalizes a raw vault.json object, for settings that arrive over the wire from a server rather than from disk.
type WriteTemplateInput ¶
type WriteTemplateInput struct {
Slug string `json:"slug"`
Raw string `json:"raw"`
PreviousSourcePath string `json:"previousSourcePath,omitempty"`
}
WriteTemplateInput saves a custom template under a slug.