Documentation
¶
Overview ¶
Package pane holds what the full-screen detail views — the comment section and reader mode — share: the content-aware viewport and search engine, frame chrome and footers, browser commands, and the standalone runner.
Index ¶
- Constants
- Variables
- func CancelledStatus() string
- func ClearProgress()
- func CommittedSearchLabel(query, icon string, enableNerdFonts bool) string
- func DepthBadge(trail []message.TrailEntry) string
- func DetectGraphics() tea.Cmd
- func DetectStyledUnderline() tea.Cmd
- func EmitKittyWork(work []article.KittyWork)
- func ExtractPromptCursor(frame string) (x, y int, cleaned string, ok bool)
- func FetchPage(ctx context.Context, fetchID uint64, url string, trail []message.TrailEntry) tea.Cmd
- func FetchThread(ctx context.Context, fetchID uint64, fetch ThreadFetcher, id int, ...) tea.Cmd
- func FirstLinkOnScreen(links []Link, top, height int) int
- func FooterSeparator(width int) string
- func FooterSeparatorWithLabel(width, rightEdge int, label string, termFG, termBG color.Color) string
- func FriendlyError(err error) string
- func HandleGraphicsReport(msg tea.Msg) bool
- func LinkOnScreen(l Link, top, height int) bool
- func LinkSelectorLabel(viewable, nerdFonts bool) string
- func LinkURLRow(paneWidth, leftMargin, contentWidth int, url string, ...) string
- func LinkViewable(rawURL string) bool
- func LoadingTitleHeader(title string, enableNerdFonts bool, leftMargin, screenWidth int) string
- func MatchCountLabel(current, total int) string
- func MatchTotalLabel(total int) string
- func MoveLink(links []Link, current, direction, top int) int
- func NewSpinner() spinner.Model
- func NewViewport(width, height int) viewport.Model
- func OpenCommentsInBrowser(id int) tea.Cmd
- func OpenStoryInBrowser(url string, id int) tea.Cmd
- func OverlayStatus(view, status string, width int) string
- func PromptLabel(input string, enableNerdFonts bool) string
- func PromptSigilWidth(enableNerdFonts bool) int
- func QueryCellSize() tea.Cmd
- func RepaintAfterGrow() tea.Cmd
- func RunStandalone(title string, makeView func(width, height int) View, opts StandaloneOptions) error
- func SaveWindowTitle() (restore func())
- func SetProgressIndeterminate()
- func SetProgressPercent(pct int)
- func SyncProgress(err error)
- func TitleHeader(title string, enableNerdFonts bool, leftMargin, screenWidth int) string
- func TitleHeaderWithBadge(title, badge string, enableNerdFonts bool, ...) string
- func UpdateSpinner(sp spinner.Model, msg spinner.TickMsg, active bool) (spinner.Model, tea.Cmd)
- func WindowTitle(text string) string
- func WireGraphics(p *tea.Program) (stop func())
- func WireProgress(p *tea.Program) (settle func())
- type CommonKeyMap
- type FetchGuard
- type FetchToken
- type Link
- type MakePageView
- type MakeThreadView
- type Match
- type PromptResult
- type RowOverride
- type Scroller
- func (s *Scroller) ActiveQuery() string
- func (s *Scroller) ClampScroll(before int)
- func (s *Scroller) ClearSearch()
- func (s *Scroller) DecorateView(view string) string
- func (s *Scroller) Forward(msg tea.Msg) tea.Cmd
- func (s *Scroller) GotoBottom()
- func (s *Scroller) HalfPageDown()
- func (s *Scroller) HalfPageUp()
- func (s *Scroller) HandleMouseWheel(msg tea.MouseWheelMsg)
- func (s *Scroller) HandleSearchPromptKey(msg tea.KeyPressMsg) PromptResult
- func (s *Scroller) JumpToFirstMatchFrom(line int)
- func (s *Scroller) JumpToMatch(i int)
- func (s *Scroller) Lines() []string
- func (s *Scroller) LinkFetching() bool
- func (s *Scroller) LinkSpans() []Match
- func (s *Scroller) LinkSpansInert() bool
- func (s *Scroller) LinkSpansThread() bool
- func (s *Scroller) NextMatch()
- func (s *Scroller) PageDown()
- func (s *Scroller) PageUp()
- func (s *Scroller) PlainLines() []string
- func (s *Scroller) PrevMatch()
- func (s *Scroller) RefreshPadding()
- func (s *Scroller) SearchActive() bool
- func (s *Scroller) SearchCountLabel() string
- func (s *Scroller) SearchFooterLabel(enableNerdFonts bool) string
- func (s *Scroller) SearchMatches() []Match
- func (s *Scroller) SearchPrompting() bool
- func (s *Scroller) SearchQuery() string
- func (s *Scroller) SetCurrentMatch(i int)
- func (s *Scroller) SetLines(lines []string)
- func (s *Scroller) SetLinkFetching(active bool)
- func (s *Scroller) SetLinkSpans(matches []Match, inert, thread bool)
- func (s *Scroller) SetRowOverrides(overrides []RowOverride)
- func (s *Scroller) SetSearchMatches(matches []Match)
- func (s *Scroller) StartSearchPrompt()
- type StandaloneOptions
- type TextPrompt
- type ThreadFetcher
- type TransientStatus
- type View
Constants ¶
const ( StatusMessageShort = 2 * time.Second StatusMessageLong = 3 * time.Second )
const ReaderFetchTimeout = 15 * time.Second
ReaderFetchTimeout bounds fetching and parsing a page for reader mode — a story's article or a followed link — in both shells. One constant, so the two cannot drift apart.
Variables ¶
var CancelKeys = key.NewBinding(key.WithKeys("esc", "backspace", "ctrl+c"))
CancelKeys stops an in-flight fetch; the app's keymap shares it so both shells cancel on the same keys.
var ProgressOut io.Writer = os.Stderr
var TitleOut io.Writer = os.Stdout
Functions ¶
func CancelledStatus ¶
func CancelledStatus() string
CancelledStatus is the message shown when an in-flight operation is cancelled by hand.
func ClearProgress ¶
func ClearProgress()
func CommittedSearchLabel ¶
CommittedSearchLabel renders a committed query dimmed behind its sigil. Nerd fonts trade the / for the done-searching glyph — icon overrides it, empty picks the shared default; views that keep the plain sigil even under nerd fonts (the front page) pass enableNerdFonts=false.
func DepthBadge ¶
func DepthBadge(trail []message.TrailEntry) string
DepthBadge marks a page reached by following links in place: one chevron per page behind it, each one a quit-key step back, colored by what that step lands on — yellow for a comment section, matching thread links in running text, green for an article. The faint fallback keeps a linked page with no chain at all from rendering an empty badge.
func DetectGraphics ¶
DetectGraphics probes the terminal for the Kitty graphics protocol and its cell pixel size, enabling high-resolution reader images. Terminals that answer confirm through HandleGraphicsReport; no answer leaves the half-block art. Terminals the probe would misfire on return nil.
func DetectStyledUnderline ¶
DetectStyledUnderline resolves whether the terminal can draw the dashed underline inert reader links use. iTerm2, Alacritty and VTE-based terminals (0.52+) draw styled underlines but do not answer XTGETTCAP, so their environment markers enable it directly. Apple's Terminal.app prints DCS queries to the screen instead of consuming them, so it is never queried. Every other terminal is asked for the Smulx terminfo capability and affirms it with a CapabilityMsg; no answer leaves the plain underline.
func EmitKittyWork ¶
EmitKittyWork queues a render's image work — PNGs not yet transmitted, placements whose geometry changed — for ordered delivery to the terminal. Call from the update loop only: submission order must match the render order the delta protocol's bookkeeping saw.
func ExtractPromptCursor ¶
ExtractPromptCursor locates the prompt cursor in a rendered frame, blanks its cell and reports the position, for the program to park the real terminal cursor there — the cursor the terminal draws in its own configured color and blink. Every open search prompt lives in a footer or status row, so only the frame's last line is scanned; ok is false when no prompt is open. The typed query itself may contain the marker rune — the cursor is appended after the input, so the last occurrence is the cursor.
func FetchPage ¶
FetchPage loads a page reached by following a link inside an article, for whichever shell dispatched it. Unlike a story fetch there is no story: no title to validate against, and nothing marked read. trail rides along untouched — it becomes the new page's walk-back chain.
func FetchThread ¶
func FetchThread(ctx context.Context, fetchID uint64, fetch ThreadFetcher, id int, trail []message.TrailEntry) tea.Cmd
FetchThread loads a Hacker News discussion linked inside an article, for the standalone shells. Nothing is marked read — the one-shot commands leave no history — so the thread arrives as if fully visited, exactly as the comments subcommand serves its own.
func FirstLinkOnScreen ¶
FirstLinkOnScreen is the topmost link in the viewport window, or -1 with none in view.
func FooterSeparator ¶
func FooterSeparatorWithLabel ¶
func FooterSeparatorWithLabel(width, rightEdge int, label string, termFG, termBG color.Color) string
FooterSeparatorWithLabel is FooterSeparator with label written into the rule, ending at rightEdge. The label's glyphs render dim while the underline through them keeps the rule's full strength: the underline color is pinned to the rule's own (SGR 58) and the text dims through an explicitly blended foreground — SGR faint cannot deliver this, terminals dim the underline decoration along with the glyphs no matter the underline color. termFG/termBG are the terminal's reported colors; without them the blend has no inputs and the label falls back to faint, dimming its stretch of the rule with it.
func FriendlyError ¶
func HandleGraphicsReport ¶
HandleGraphicsReport records a terminal's answer to the graphics probes and reports whether the state changed — the caller then repaints an open reader so its images pick up the new mode or geometry.
func LinkOnScreen ¶
LinkOnScreen reports whether any of the link's spans lies in the viewport window starting at top, height lines tall.
func LinkSelectorLabel ¶
LinkSelectorLabel is the footer label while a URL selector is up: the selector icon and a faint mode label, while the URL itself rides the separator above. A link the view won't open breaks the arrow, matching its dimmed URL; an empty selection keeps the plain arrow — nothing is inert, there is just nothing selected yet.
func LinkURLRow ¶
func LinkURLRow(paneWidth, leftMargin, contentWidth int, url string, termFG, termBG color.Color) string
LinkURLRow is the footer separator while a URL selector is up: the selected link's URL written into the rule, right-aligned against the content column's edge, leaving the footer line to the mode label. The URL renders faint under the rule's full-strength underline; whether the link opens shows in the footer arrow and the selection bar, not here.
func LinkViewable ¶
LinkViewable reports whether following the link can open a view in place: a page reader mode could render, or a Hacker News discussion the comment section opens. Links that can't (PDFs, media, archives, blocked domains) are selectable but inert, marked by the red selection bar and a dimmed footer URL.
func LoadingTitleHeader ¶
LoadingTitleHeader is TitleHeader without the bold: the detail pane shows it while the story loads and on the error view when the load fails, so the title gains its full weight only once the content is in.
func MatchCountLabel ¶
MatchCountLabel is the "3/17" match counter, or "no matches".
func MatchTotalLabel ¶
MatchTotalLabel is the counter while the prompt is open: hits have no current position yet, so only the running total shows.
func MoveLink ¶
MoveLink selects the next link wherever it sits, wrapping like a search jump. From an empty selection (-1) it leaves relative to the viewport: forward to the first link past its top, backward to the last one above it.
func NewSpinner ¶
func NewViewport ¶
NewViewport returns a viewport with the bindings the detail views handle themselves (paging) disabled, along with mouse wheel handling. Horizontal scrolling is disabled entirely: pane content is pre-wrapped to fit, and DecorateView's row mapping relies on a zero x-offset.
func OpenCommentsInBrowser ¶
func OpenStoryInBrowser ¶
OpenStoryInBrowser opens the story URL, falling back to the HN item page for text posts. Returns nil when there is nothing to open (standalone reader on an arbitrary URL-less item).
func OverlayStatus ¶
OverlayStatus writes fetch and status feedback onto the last row of a detail view, which reserves that row as footer space. width is the pane the view fills.
func PromptLabel ¶
PromptLabel renders an open prompt: the sigil zone, the typed text and the cursor.
func PromptSigilWidth ¶
PromptSigilWidth is the cells the prompt zone occupies before the typed text. Views that keep the text column identical between the open prompt and the committed query outdent the prompt by the difference.
func QueryCellSize ¶
QueryCellSize re-asks for the cell pixel size on a resize, so a font-size change re-derives image geometry. Nothing to keep honest before the graphics probe succeeded.
func RepaintAfterGrow ¶
RepaintAfterGrow works around a renderer bug that surfaces when the terminal grows wider: ultraviolet resizes its model of the screen but backfills only newly added rows, never the columns a grow adds to existing rows (TerminalRenderer.Render's sync loop), so it records those columns as blank while the resize redraw put content there. Anything in them that later becomes blank diffs as unchanged and lingers on screen as ghost text. A full repaint after that redraw has flushed — once the model has its correct dimensions — resyncs the model with the screen.
func RunStandalone ¶
func RunStandalone(title string, makeView func(width, height int) View, opts StandaloneOptions) error
RunStandalone runs a detail view as its own program under the window title title; makeView receives the terminal dimensions from the first WindowSizeMsg. The options' factories let links followed inside the view open in place; absent ones fall back to the browser.
func SaveWindowTitle ¶
func SaveWindowTitle() (restore func())
SaveWindowTitle pushes the terminal's current window title and returns the pop that restores it. Call it before the program starts and the restore after it exits: like the progress sequences, a direct write is only safe where no frame flush can interleave with it.
func SetProgressIndeterminate ¶
func SetProgressIndeterminate()
func SetProgressPercent ¶
func SetProgressPercent(pct int)
func SyncProgress ¶
func SyncProgress(err error)
SyncProgress settles the indicator for a finished fetch: an error stays visible for the status message lifetime, success clears it. Call only from the Update loop after the finish guard, so a stale fetch can never write over its successor's indicator.
func TitleHeader ¶
TitleHeader renders the bold, highlighted story title over an underline separator spanning the screen.
func TitleHeaderWithBadge ¶
func TitleHeaderWithBadge(title, badge string, enableNerdFonts bool, leftMargin, rightEdge, screenWidth int) string
TitleHeaderWithBadge is TitleHeader with a pre-styled badge ending at rightEdge — the content column's right edge, not the screen's. The title truncates early enough that the two never collide. A pane too narrow to keep any title next to the badge drops the badge instead.
func UpdateSpinner ¶
UpdateSpinner advances the animation and reschedules the next tick only while active, so a stopped spinner's tick chain dies out.
func WindowTitle ¶
WindowTitle prepares text for use as a window title. OSC 2 ends at the first BEL or ST, so a control character in a story title would close the sequence early and let whatever follows land on the terminal as commands. Titles are already stripped at ingest — this is the sink saying so itself, as ansi.Hyperlink does for its target.
func WireGraphics ¶
WireGraphics routes image work into p's message loop. Call it before Run; the returned stop ends the worker once the program has exited.
func WireProgress ¶
WireProgress routes progress sequences into p's message loop. Call it before Run: the pre-start write to progressCh is the happens-before edge that lets fetch goroutines read it without locks. The forwarder goroutine exists because Send would deadlock called from Update itself; once the program stops, Send is a no-op. The returned settle stops the forwarder and clears the indicator — call it after Run returns, when a direct write can no longer interleave with a frame; clearing there rather than in the quit paths guarantees the indicator never outlives the program, whatever the exit.
Types ¶
type CommonKeyMap ¶
type CommonKeyMap struct {
Quit key.Binding
Help key.Binding
GotoTop key.Binding
GotoBottom key.Binding
HalfPageDown key.Binding
HalfPageUp key.Binding
PageDown key.Binding
PageUp key.Binding
OpenLink key.Binding
OpenComments key.Binding
NextStory key.Binding
PrevStory key.Binding
ToggleWide key.Binding
// Search bindings apply while a search is active; n/N then take
// precedence over each view's own jump bindings.
Search key.Binding
NextMatch key.Binding
PrevMatch key.Binding
ClearSearch key.Binding
}
CommonKeyMap holds the bindings shared by both detail views; each view embeds it and adds its own.
func DefaultCommonKeyMap ¶
func DefaultCommonKeyMap() CommonKeyMap
func (*CommonKeyMap) DisableAppKeys ¶
func (k *CommonKeyMap) DisableAppKeys()
DisableAppKeys removes the bindings that need the surrounding app — the J/K adjacent-story jumps and the z layout toggle — for standalone use where there is no story list and no split layout.
type FetchGuard ¶
type FetchGuard struct {
// contains filtered or unexported fields
}
FetchGuard owns the identity and cancellation of the single fetch a shell allows in flight. Begin invalidates any predecessor and hands out the new fetch's token; Finish drops stale results; Abort cancels and moves to a new era, so a result the fetch managed to deliver before the cancel took hold can never match.
func (*FetchGuard) Abort ¶
func (g *FetchGuard) Abort() bool
Abort cancels the in-flight fetch; false means nothing was in flight.
func (*FetchGuard) Begin ¶
func (g *FetchGuard) Begin(timeout time.Duration) FetchToken
Begin starts a fetch's lifecycle, invalidating any predecessor. A zero timeout means the fetch runs until finished or aborted.
func (*FetchGuard) CurrentID ¶
func (g *FetchGuard) CurrentID() uint64
CurrentID stamps era-scoped side effects made outside Begin (e.g. an error-display timeout) so they can be ignored once a newer fetch begins.
func (*FetchGuard) Finish ¶
func (g *FetchGuard) Finish(id uint64) bool
Finish ends the in-flight fetch if id belongs to it; false is a stale result the caller must drop.
func (*FetchGuard) InFlight ¶
func (g *FetchGuard) InFlight() bool
type FetchToken ¶
type FetchToken struct {
Ctx context.Context //nolint:containedctx // fetch-scoped, never stored beyond the Update cycle
ID uint64
}
FetchToken is a fetch's identity: the context its commands must fetch under and the id their results must carry. Only Begin hands one out, so a fetch command can only be built for the fetch actually starting. A token held across Update cycles goes stale — results built from it fail the Finish guard and are dropped.
type Link ¶
Link is one followable URL in a rendered document: the OSC 8 target and the cell spans its anchor text occupies — one span per rendered line for links the wrap split. Thread marks a Hacker News discussion link, whose selection paints in thread yellow rather than link blue.
func ExtractLinks ¶
ExtractLinks locates every OSC 8 hyperlink in the rendered lines from fromLine on. The wrapper closes and reopens a hyperlink at each line break, so spans of the same URL on adjacent lines are one link, while the same URL opening twice on one line — or in separate paragraphs, a blank line apart — is two.
type MakePageView ¶
type MakePageView func(entry message.TrailEntry, trail []message.TrailEntry, width, height int) View
MakePageView rebuilds a reader page around a followed link — opening one, or walking back through the trail. entry carries the page's parse, trail the chain behind it.
type MakeThreadView ¶
type MakeThreadView func(thread *comment.Thread, lastVisited int64, trail []message.TrailEntry, width, height int) View
MakeThreadView rebuilds a comment section around a followed Hacker News discussion link — opening one, or walking back through the trail.
type Match ¶
Match locates one search hit: a cell span on a content line.
func FindMatches ¶
FindMatches locates query in the given plain lines as cell spans. Smart case: an all-lowercase query matches case-insensitively, any uppercase character makes the match exact.
type PromptResult ¶
type PromptResult int
PromptResult reports how the search prompt reacted to a key press.
const ( PromptPending PromptResult = iota PromptCommitted PromptCanceled )
type RowOverride ¶
RowOverride substitutes the rendered row at content line Line for display only, leaving the stored content untouched. The comment section uses it to swap in the focused header variant without rebuilding the document.
type Scroller ¶
type Scroller struct {
Viewport viewport.Model
ContentLines int // excludes bottom padding
// SearchCommittedIcon replaces the shared done-searching glyph in the
// footer's search label; empty keeps the default.
SearchCommittedIcon string
// contains filtered or unexported fields
}
Scroller wraps a viewport with content-aware scrolling: paging and clamping are computed against the real content length, ignoring the bottom padding SetLines appends so any line can scroll to the top.
func (*Scroller) ActiveQuery ¶
ActiveQuery is the text matches should be computed against: the live prompt input while typing, the committed query otherwise. Views recompute matches from it on every prompt key, so hits highlight as the user types, and a canceled prompt falls back to the prior query's matches.
func (*Scroller) ClampScroll ¶
ClampScroll prevents scrolling down past the last content line while still allowing upward scrolling from a position beyond the clamp point (e.g. after an n/N jump).
func (*Scroller) ClearSearch ¶
func (s *Scroller) ClearSearch()
ClearSearch drops the query and matches; highlights disappear on the next frame since DecorateView applies them per render.
func (*Scroller) DecorateView ¶
DecorateView applies the display-time decorations to the viewport's rendered window: row overrides first, then search-match overlays on top, so a match inside a focused header highlights the focused variant. Row k of the view shows content line YOffset+k — the invariant that makes this mapping valid is that pane content never scrolls horizontally.
func (*Scroller) GotoBottom ¶
func (s *Scroller) GotoBottom()
GotoBottom scrolls the last line of real content to the bottom of the viewport, ignoring the bottom padding.
func (*Scroller) HalfPageDown ¶
func (s *Scroller) HalfPageDown()
func (*Scroller) HalfPageUp ¶
func (s *Scroller) HalfPageUp()
func (*Scroller) HandleMouseWheel ¶
func (s *Scroller) HandleMouseWheel(msg tea.MouseWheelMsg)
func (*Scroller) HandleSearchPromptKey ¶
func (s *Scroller) HandleSearchPromptKey(msg tea.KeyPressMsg) PromptResult
HandleSearchPromptKey feeds one key press to the open search prompt; a commit installs the typed text as the query, leaving any previous search untouched on cancel.
func (*Scroller) JumpToFirstMatchFrom ¶
JumpToFirstMatchFrom jumps to the first match at or below the given line, wrapping to the first match overall when none follows.
func (*Scroller) JumpToMatch ¶
JumpToMatch scrolls match i (wrapped into range) to sit a couple of lines below the viewport top and makes it the current match.
func (*Scroller) Lines ¶
Lines is the stored content as styled lines, for views that scan the rendered output itself (the reader's link extraction).
func (*Scroller) LinkFetching ¶
func (*Scroller) LinkSpansInert ¶
func (*Scroller) LinkSpansThread ¶
func (*Scroller) PlainLines ¶
PlainLines is the content with ANSI styling stripped — the text as the user sees it, for matching against. Stripped on first use after a content change, so views that never need it don't pay for it. xansi.Strip (a parser walk) is used over ansi.Strip (a backtracking regexp): measured ~6× faster on escape-heavy content like image art.
func (*Scroller) RefreshPadding ¶
func (s *Scroller) RefreshPadding()
RefreshPadding re-pushes the stored content so the bottom padding matches the current viewport height, for height-only resizes where the content itself is unchanged.
func (*Scroller) SearchActive ¶
SearchActive reports whether a committed query is in effect.
func (*Scroller) SearchCountLabel ¶
SearchCountLabel is the counter over the Scroller's own match list; views that navigate a larger match set format theirs with MatchCountLabel and MatchTotalLabel.
func (*Scroller) SearchFooterLabel ¶
SearchFooterLabel is the footer text for the search state: the live prompt with a block cursor while typing, the committed query dimmed otherwise, empty when no search is in play. Nerd fonts swap the faint / for a magnifier at full strength, like the footer's other icons, with extra room after the wide glyph; committing trades the magnifier for a done-searching glyph, SearchCommittedIcon or the shared default.
func (*Scroller) SearchMatches ¶
func (*Scroller) SearchPrompting ¶
func (*Scroller) SearchQuery ¶
func (*Scroller) SetCurrentMatch ¶
SetCurrentMatch marks matches[i] as the current match for highlighting, for views that run match navigation outside the Scroller; -1 means the current match isn't in the installed list (hidden in a collapsed branch). Views that navigate through JumpToMatch/NextMatch/PrevMatch never call this — the jumps track the current match themselves.
func (*Scroller) SetLines ¶
SetLines replaces the viewport content. A viewport-height of padding is appended so jump targets near the end can scroll to the top of the view; ClampScroll keeps ordinary scrolling within the real content.
func (*Scroller) SetLinkFetching ¶
SetLinkFetching repaints the selection in the muted in-flight colors while the followed link's fetch runs. The shell that owns the fetch toggles it: on at fetch start, off when the fetch ends without a page (failure, cancel) — success replaces the view, taking the state with it.
func (*Scroller) SetLinkSpans ¶
SetLinkSpans installs the spans of the link the reader's URL selector sits on; nil clears them. They paint over any search highlights — the selection is the thing being acted on. inert swaps the selection colors for the red bar, marking a link the view will not open; thread swaps them for the yellow bar of a Hacker News discussion link.
func (*Scroller) SetRowOverrides ¶
func (s *Scroller) SetRowOverrides(overrides []RowOverride)
SetRowOverrides installs the display-time row substitutions. Overrides must not change a row's visible width.
func (*Scroller) SetSearchMatches ¶
SetSearchMatches installs the match list for the committed query. The caller computes the matches — how content maps to matchable text differs per view. Highlighting happens in DecorateView.
func (*Scroller) StartSearchPrompt ¶
func (s *Scroller) StartSearchPrompt()
type StandaloneOptions ¶
type StandaloneOptions struct {
MakePageView MakePageView
MakeThreadView MakeThreadView
FetchThread ThreadFetcher
}
StandaloneOptions carries the factories a standalone shell follows links with. A nil factory sends its kind of link to the browser instead, so each subcommand grants exactly the views it can build.
type TextPrompt ¶
type TextPrompt struct {
// contains filtered or unexported fields
}
TextPrompt is a one-line text input: the Scroller's search prompt and the front page's Hacker News search share its key handling, so the two prompts can never drift apart in feel.
func (*TextPrompt) Active ¶
func (p *TextPrompt) Active() bool
func (*TextPrompt) HandleKey ¶
func (p *TextPrompt) HandleKey(msg tea.KeyPressMsg) PromptResult
HandleKey feeds one key press to the open prompt. Printable characters append, enter commits the typed text, esc and backspacing past empty cancel. Committing an empty prompt also cancels.
func (*TextPrompt) Start ¶
func (p *TextPrompt) Start()
func (*TextPrompt) Text ¶
func (p *TextPrompt) Text() string
Text is the typed input; after PromptCommitted it holds the committed text.
type ThreadFetcher ¶
type ThreadFetcher func(ctx context.Context, id int, onProgress func(fetched, total int)) (*comment.Thread, error)
ThreadFetcher loads a Hacker News discussion as the comment views consume it. The cmd layer supplies one wrapping its service, so this package stays ignorant of which backend answers.
type TransientStatus ¶
type TransientStatus struct {
// contains filtered or unexported fields
}
TransientStatus is a footer status message that expires after a lifetime; the generation guards a stale timer from clearing a newer message.
func (*TransientStatus) Clear ¶
func (t *TransientStatus) Clear()
Clear hides the message immediately and invalidates pending expiries.
func (*TransientStatus) Expire ¶
func (t *TransientStatus) Expire(gen int) bool
Expire clears the message if gen is current — i.e. the timer that fired belongs to the visible message — and reports whether it did.
func (*TransientStatus) Message ¶
func (t *TransientStatus) Message() string
func (*TransientStatus) SetPermanent ¶
func (t *TransientStatus) SetPermanent(msg string)
SetPermanent shows msg with no expiry: it stays until the next Set, SetPermanent or Clear. The generation bump invalidates pending expiry timers — the message may be modal text like the favorites prompt, which an earlier message's timer must not blank.