Documentation
¶
Index ¶
- func FilterScope(allTicks []tick.Tick, scope Scope, owner string) []tick.Tick
- func PinColorProfile(p termenv.Profile)
- func RenderRoadmap(allTicks []tick.Tick, width int) string
- func RenderRoadmapWithSelection(allTicks []tick.Tick, width int, selectedID string) (string, int)
- func SaveState(storePath string, s PersistedState) error
- type App
- type PersistedState
- type Scope
- type ScopeAware
- type Selector
- type Sidebar
- type Sizable
- type View
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FilterScope ¶ added in v0.18.0
FilterScope filters allTicks to the set a content view should render for the given scope (§4–§5). Smart views are cross-cutting queries; a tree node scopes to that node's subtree (the node plus its descendants).
func PinColorProfile ¶ added in v0.18.0
PinColorProfile fixes the lipgloss/termenv color profile process-wide. It replaces the old `COLORTERM=truecolor` init() hack in model.go with an explicit, test-pinnable seam (§11 determinism pins): production pins TrueColor so terminals that misreport (e.g. TERM=screen under tmux) still get full color; tests pin a fixed profile so ANSI output does not vary by environment.
tui.PinColorProfile(termenv.TrueColor) // production tui.PinColorProfile(termenv.Ascii) // golden tests (no ANSI noise)
func RenderRoadmap ¶ added in v0.13.0
RenderRoadmap renders the roadmap view for the left pane. It takes the full tick slice (to call ComputeRoadmap) and the available width for the pane. The function is pure (no model state) so it is trivially unit-testable.
Visual layout per epic line:
<glyph> <id> [closed/total] <title> [gate-badge] [← blocked by: id1 id2] [← after: id1 id2]
Each wave is preceded by a "Wave N" header (1-indexed).
func RenderRoadmapWithSelection ¶ added in v0.16.0
RenderRoadmapWithSelection renders the roadmap like RenderRoadmap, but the epic whose ID matches selectedID gets a "> " cursor and the tree's selection style; all other lines keep their per-segment styles (status glyph, blocked and after annotations) untouched. It also returns the 0-based content line index of the selected epic line (-1 when nothing is selected) so callers can scroll it into view.
func SaveState ¶ added in v0.18.0
func SaveState(storePath string, s PersistedState) error
SaveState writes the current App state to .tick/<stateFileName> in the store path. The file is created (or truncated) with mode 0o644. Errors are returned to the caller; the .tick dir must already exist.
Types ¶
type App ¶ added in v0.18.0
type App struct {
// contains filtered or unexported fields
}
App is the root model (§2): it owns global focus, terminal size, the active scope (selected sidebar node), the active content view, and the view registry. It routes Update/View to the focused child and picks the adaptive 3/2/1-pane layout by terminal width (§3, layout.go).
func NewApp ¶ added in v0.18.0
NewApp builds the root model from the filtered tick set, the store path, and the current user. It wires the sidebar, the view registry (List registered), and the read-only detail stub.
func (*App) ApplyState ¶ added in v0.18.0
func (a *App) ApplyState(s PersistedState)
ApplyState restores the PersistedState into the App fields. Call this after NewApp but before tea.NewProgram.
func (*App) ExtractState ¶ added in v0.18.0
func (a *App) ExtractState() PersistedState
ExtractState snapshots the App fields that belong in PersistedState. Call this just before tea.NewProgram exits (i.e. after Run() returns).
func (App) Init ¶ added in v0.18.0
Init satisfies tea.Model; it starts the filesystem watcher if available.
type PersistedState ¶ added in v0.18.0
type PersistedState struct {
// ActiveViewIndex is App.activeIx — which content view is shown (0=List …).
ActiveViewIndex int `json:"activeViewIndex"`
// Scope is App.scope — the selected sidebar row (smart view or tree node).
Scope Scope `json:"scope"`
// CollapsedNodes is Sidebar.collapsed — set of tick IDs whose tree rows are
// collapsed. The zero value (nil map) means nothing is collapsed.
CollapsedNodes map[string]bool `json:"collapsedNodes,omitempty"`
// Focus is App.focus — which pane (sidebar/main/detail) holds keyboard focus.
Focus focusZone `json:"focus"`
// DetailVisible is App.detailVisible — whether the detail pane is shown in
// narrow (2/1-pane) layouts.
DetailVisible bool `json:"detailVisible"`
}
PersistedState is the subset of App state that survives across sessions. It is serialised to JSON as .tick/.tui-state.json on quit and loaded before the first tea.NewProgram call.
Fields map directly to App internals — no re-definition: the types (Scope, focusZone, etc.) are the same ones App uses.
func DefaultState ¶ added in v0.18.0
func DefaultState() PersistedState
DefaultState returns a PersistedState with sensible defaults matching NewApp's initial values (focusSidebar, first smart-view, all expanded, etc.).
func LoadState ¶ added in v0.18.0
func LoadState(storePath string) (PersistedState, error)
LoadState reads .tick/<stateFileName> from the given store path and returns the decoded state. If the file does not exist the defaults are returned with no error. Any other I/O or JSON error is returned to the caller.
type Scope ¶ added in v0.18.0
type Scope struct {
Kind scopeKind
Smart smartViewKind // valid when Kind == scopeSmart
Node string // tick ID, valid when Kind == scopeNode
}
Scope is the App's active selection: either one of the smart views or a node in the project tree. Selecting a sidebar row sets the App's Scope, which the content views read to decide what set of ticks to show (§4).
type ScopeAware ¶ added in v0.18.0
ScopeAware is implemented by views that react to the active sidebar scope and the underlying tick set. The App calls SetScope when the selection in the sidebar changes or the ticks reload.
type Selector ¶ added in v0.18.0
type Selector interface {
SelectedTickID() string
}
Selector is implemented by views that track a "current" tick so the detail pane can mirror the highlighted row. Returns "" when nothing is selected.
type Sidebar ¶ added in v0.18.0
type Sidebar struct {
// contains filtered or unexported fields
}
Sidebar is the left navigation pane: two stacked lists (smart views + the collapsible project tree). It owns its own selection cursor and collapse state; selecting a row yields a Scope via SelectedScope (§4).
func NewSidebar ¶ added in v0.18.0
NewSidebar builds the sidebar from the full tick set and the current user.
func (*Sidebar) SelectNode ¶ added in v0.18.0
SelectNode moves the sidebar cursor to the tree node for the given tick ID. This is used by the App's jumpToEpicMsg handler to point the sidebar at the jumped-to epic. If the ID is not present in the current row list (e.g. the sidebar has no project tree for that ID) the selection is left unchanged.
func (*Sidebar) SelectedScope ¶ added in v0.18.0
SelectedScope returns the Scope for the currently highlighted row. When the selection rests on a non-selectable row (heading) or there are no rows, it falls back to the Awaiting smart view.
func (*Sidebar) SetTicks ¶ added in v0.18.0
SetTicks updates the underlying ticks and rebuilds the row list, preserving the current selection by identity where possible.
func (Sidebar) Update ¶ added in v0.18.0
Update handles navigation and collapse/expand for the sidebar (§4). It moves the selection cursor (j/k or arrows), and toggles tree-node collapse on space/enter. It returns the updated sidebar and whether the selected scope changed (so the App can re-scope the content views).
type Sizable ¶ added in v0.18.0
type Sizable interface {
SetSize(width, height int)
}
Sizable is implemented by views that need to know their content dimensions. The App calls SetSize whenever the layout changes. Views that render purely from data may ignore size and omit this.
type View ¶ added in v0.18.0
type View interface {
// Update handles a message and returns the (possibly mutated) view plus an
// optional command. Views are value types: return the updated copy.
Update(tea.Msg) (View, tea.Cmd)
// View renders the view body to a string sized to the most recent
// SetSize call.
View() string
// Title is the human-readable view name shown in the content header.
Title() string
// Tab is the short label shown in the view-tab strip (e.g. "List").
Tab() string
}
View is a swappable content view-model for the main pane (§2, §5). Each view renders the App's current scope over the shared tick set. Views are small Update/View pairs, testable in isolation.
The interface is deliberately minimal so downstream view ticks (Board, Roadmap, Timeline) can implement it cheaply and register with one line. It is the load-bearing seam every later view tick depends on — change it only with care.