remote

package
v0.35.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package remote binds a component to a remote source, so a screen supplies only what varies between APIs — the fetch — and nothing of the routing between them.

Without it, a screen showing paged remote data is the glue between two halves of one state machine: it forwards the component's viewport to the source, mirrors what the component holds back into it, turns each kind of reply into the right component call, lands search hits, keeps "growing" set on both, and replays all of it after a theme swap in the right order. Every one of those is an ordering rule a screen can get wrong silently. Here they live once:

s.log = remote.NewEventlog(t.Eventlog(), remote.Seekable[eventlog.Item]{
    Page: s.page,   // func(ctx, remote.Window) ([]eventlog.Item, total int, error)
    Find: s.find,   // optional: nil searches only what is loaded
})

func (s *Screen) Init() tea.Cmd { return s.log.Init() }
func (s *Screen) Update(msg tea.Msg) (screen.Screen, tea.Cmd) {
    return s, s.log.Update(msg)
}
func (s *Screen) SetTheme(t theme.Theme) { s.log.Restyle(t.Eventlog()) }

The fetch functions are ordinary synchronous Go: take a context and a typed request, return the items. They run off the UI goroutine, their context is cancelled when a newer request supersedes them, and a reply nobody is waiting for is dropped — none of which the function sees.

Each shape of data (CLAUDE.md rule 34) has its own request type: Seekable data is asked for by Window (offset and limit), Anchored data by Edge (a direction and the cursor to walk from), and both can answer a Find. Growing data is one call: SetGrowing. Anchored data starts at Anchored.Anchor and moves with SetAnchor.

The views embed their component, so everything else — Selected, IsActivate, focus, help, SetRect — is the component's own. pkg/source, pkg/table and pkg/eventlog stay public for anything this doesn't cover.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Anchored

type Anchored[T any] struct {
	// Edge returns the items of e, oldest first, and whether that edge has
	// more beyond them. Each item's key is its cursor.
	Edge func(ctx context.Context, e Edge) (items []T, more bool, err error)
	// Find returns the cursor of the first match, and whether there was
	// one. The view re-anchors there. Nil searches only what is loaded.
	Find func(ctx context.Context, f Find) (cursor string, found bool, err error)

	// Name, PageSize, Follow, ViewportDelay and Context mean what they do
	// on source.AnchoredOptions. There is no Prefetch: an edge is extended
	// once the viewport comes within PageSize of it, which is already a
	// page of lookahead.
	// Anchor is where the view starts: source.Newest() (the zero value),
	// source.Oldest(), or source.At(cursor), which lands on that item.
	Anchor source.Anchor

	Name          string
	PageSize      int
	Follow        time.Duration
	ViewportDelay time.Duration
	Context       context.Context
}

Anchored is data reachable only by walking from an anchor.

type Edge

type Edge struct {
	Filter
	Newer     bool
	Cursor    string
	Inclusive bool
	Limit     int
}

Edge asks Anchored data for up to Limit items walking from Cursor: newer ones when Newer, older ones otherwise, oldest first either way. An empty Cursor starts at the end being walked from — the newest item for an older walk, the oldest for a newer one. Inclusive includes the item at Cursor itself: the first request of a view anchored there.

type Eventlog

type Eventlog struct {
	eventlog.Model
	// contains filtered or unexported fields
}

Eventlog is an eventlog bound to a remote source. Everything the component offers is promoted from the embedded Model; Update, Init, SetGrowing, SetAnchor and Restyle are the binding's.

func NewEventlog

func NewEventlog(opts eventlog.Options, s Shape[eventlog.Item]) *Eventlog

NewEventlog builds an eventlog over s — Seekable (a job's numbered events) or Anchored (a log searched with search_after). Start opts from theme.Eventlog(); Anchored is set from s.

func (*Eventlog) Init

func (e *Eventlog) Init() tea.Cmd

Init requests the first page.

func (*Eventlog) Refresh

func (e *Eventlog) Refresh() tea.Cmd

Refresh refetches what is on screen under the same query — a retry.

func (*Eventlog) Restyle

func (e *Eventlog) Restyle(opts eventlog.Options)

Restyle swaps in opts — a new theme — keeping everything the view holds: items, filter, search, cursor, follow and failure.

func (*Eventlog) SetAnchor added in v0.34.0

func (e *Eventlog) SetAnchor(a source.Anchor) tea.Cmd

SetAnchor moves an Anchored view to a — a "jump to time" — replacing what it holds once a's first page arrives. It does nothing on Seekable data.

func (*Eventlog) SetGrowing

func (e *Eventlog) SetGrowing(b bool) tea.Cmd

SetGrowing says whether the data is still gaining items — a job still running. While it is, the view follows and the source polls.

func (*Eventlog) Update

func (e *Eventlog) Update(msg tea.Msg) tea.Cmd

Update routes msg between the view and its source, runs fetches, and updates the view. Forward every message.

type Filter

type Filter struct {
	Raw   string
	Terms []query.Term
	Sort  string
	Desc  bool
}

Filter is the committed query a request is for: the filter text as typed, parsed into terms (scoped terms carry their resolved column title), and the sort, when the view has one.

type Find

type Find struct {
	Filter
	Term   string
	Newer  bool
	From   int
	Cursor string
}

Find asks for the first item matching Term beyond a position, within the Filter: after it when Newer, before it otherwise. Seekable data gives the position as From, and the key of the item there as Cursor — the id to search past for an API that searches by its own ids, since positions stop matching ids under a filter. Anchored data gives only Cursor.

type Seekable

type Seekable[T any] struct {
	// Page returns the items of w and the total. For Growing data the
	// total is how many exist now.
	Page func(ctx context.Context, w Window) (items []T, total int, err error)
	// Find returns the position of the first match, and whether there was
	// one. Nil searches only what is loaded.
	Find func(ctx context.Context, f Find) (at int, found bool, err error)

	// Name, PageSize, Prefetch, Follow, ViewportDelay and Context mean
	// what they do on source.Options.
	Name          string
	PageSize      int
	Prefetch      int
	Follow        time.Duration
	ViewportDelay time.Duration
	Context       context.Context
}

Seekable is data whose item N can be fetched directly, with a total.

type Shape

type Shape[T any] interface {
	// contains filtered or unexported methods
}

Shape is a source's shape: Seekable or Anchored.

type Table

type Table struct {
	table.Model
	// contains filtered or unexported fields
}

Table is a table of Records bound to a remote source: the filter and sort are the source's, and scrolling is the pagination. Everything the component offers is promoted from the embedded Model.

func NewTable

func NewTable(opts table.Options, s Shape[table.KeyedRow]) *Table

NewTable builds a table over s. Seekable data is windowed (rows carry no keys there, so marking is inert); Anchored data is a span keyed by cursor. Start opts from theme.Table(); the remote filter and sort modes, and Anchored, are set here.

func (*Table) Init

func (t *Table) Init() tea.Cmd

Init requests the first page.

func (*Table) Refresh

func (t *Table) Refresh() tea.Cmd

Refresh refetches what is on screen under the same query — a retry.

func (*Table) Restyle

func (t *Table) Restyle(opts table.Options)

Restyle swaps in opts — a new theme — keeping the rows, filter, sort (including one still staged), cursor and failure.

func (*Table) SetAnchor added in v0.34.0

func (t *Table) SetAnchor(a source.Anchor) tea.Cmd

SetAnchor moves an Anchored table to a, replacing its rows once a's first page arrives. It does nothing on Seekable data.

func (*Table) SetGrowing

func (t *Table) SetGrowing(b bool) tea.Cmd

SetGrowing says whether rows are still arriving; while they are, the source polls.

func (*Table) Update

func (t *Table) Update(msg tea.Msg) tea.Cmd

Update routes msg between the table and its source, runs fetches, and updates the table. Forward every message.

type Window

type Window struct {
	Filter
	Offset, Limit int
}

Window asks Seekable data for Limit items starting at Offset.

Jump to

Keyboard shortcuts

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