Documentation
¶
Index ¶
Constants ¶
const SearchPageSize = 10
SearchPageSize mirrors the CLI picker's displayPageSize (cmd/lmm/install.go).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ActionOutcome ¶ added in v1.11.0
type ActionOutcome struct {
Message string // one-line success summary, e.g. `Enabled "SkyUI"` / "Deployed 5 mod(s)"
Warnings []string // non-fatal diagnostics: the underlying flow result's Warnings then Notes, in that order
}
ActionOutcome is what the TUI status line renders after a successful ActionProvider call. Message and each Warnings entry are TUI-facing English composed by the provider (not core, which never prints or formats for a specific caller) and are expected to be truncated to panel width by the renderer - keep them short and specific.
type ActionProgress ¶ added in v1.12.0
ActionProgress is one streamed progress tick from an in-flight ActionProvider mutation (ApplyInstall/ApplyUpdate/ApplyProfileSwitch - see actions_provider.go). Line is a ready-to-display, provider-composed status string kept short enough for the one-row status line (e.g. `Installing SkyUI: skyui_5_1.7z 42%`); Percent is the 0-100 completion when known, or -1 when the phase has no meaningful percentage (indeterminate - e.g. "extracting").
type ActionProvider ¶ added in v1.11.0
type ActionProvider interface {
EnableMod(ctx context.Context, item ModItem) (ActionOutcome, error)
DisableMod(ctx context.Context, item ModItem) (ActionOutcome, error)
UninstallMod(ctx context.Context, item ModItem) (ActionOutcome, error)
DeployProfile(ctx context.Context) (ActionOutcome, error)
PlanProfileSwitch(ctx context.Context, profile string) (SwitchPlanView, error)
// ApplyProfileSwitch's progress may be nil (see ActionProgress); it
// streams download/install ticks when the plan being applied needs
// them (Phase 5b Task 4 - see coreProvider/prototypeProvider's own doc
// comments on this method).
ApplyProfileSwitch(ctx context.Context, profile string, progress func(ActionProgress)) (ActionOutcome, error)
// PlanInstall computes what installing item would do (files, resolved
// dependencies, conflicts, size), without mutating anything - the
// install-modal analog of PlanProfileSwitch.
PlanInstall(ctx context.Context, item ModItem) (InstallPlanView, error)
// ApplyInstall executes the plan PlanInstall would currently compute for
// item (coreProvider re-plans at apply time, mirroring
// ApplyProfileSwitch's own precedent). progress may be nil.
ApplyInstall(ctx context.Context, item ModItem, progress func(ActionProgress)) (ActionOutcome, error)
// CheckUpdates reports available updates for every checkable installed
// mod (pinned/local mods are never checkable - filtered by core, not
// re-filtered here).
CheckUpdates(ctx context.Context) (UpdatesView, error)
// ApplyUpdate applies one update reported by CheckUpdates. progress may
// be nil.
ApplyUpdate(ctx context.Context, u UpdateItem, progress func(ActionProgress)) (ActionOutcome, error)
}
ActionProvider is the write-side seam over the core mutation flows (Service.EnableMod/DisableMod/UninstallMod/DeployProfile/ PlanProfileSwitch/ApplyProfileSwitch). It is deliberately separate from DataProvider: DataProvider stays provably read-only (nothing in its interface can mutate app state), and implementations of one need not implement the other - though coreProvider and prototypeProvider both do, each on its own single struct (see NewCoreActions and NewPrototypeProvider for how a caller obtains each role).
Error semantics: an error does NOT imply nothing changed. The underlying flows are multi-step (deploy files then flip DB state; undeploy, delete cache, then delete the DB row; whole per-mod loops before SetDefault); a failure partway leaves earlier steps applied. Callers must treat any error as "state may have partially changed": refresh data after every action, success or failure, and never offer undo/retry affordances that assume a failed action was a no-op. PlanProfileSwitch and PlanInstall are the exceptions: planning is pure and never mutates either way.
Progress-callback lifetime: the progress func(ActionProgress) argument ApplyProfileSwitch/ApplyInstall/ApplyUpdate accept must never be called after the method itself has returned. buildAction (actions.go) closes the channel progress writes into immediately once the method returns, so an implementation that reports progress from a detached goroutine outliving the call risks a send-on-closed-channel panic - progress must only be invoked synchronously within the method's own call stack (or from a goroutine fully joined before returning).
func NewCoreActions ¶ added in v1.11.0
NewCoreActions returns an ActionProvider backed by the real app service, for the same (svc, game, profileName) triple NewCoreProvider takes. The two constructors are independent (coreProvider carries no in-memory-only state - every mutation goes through svc's DB/filesystem, so two separate instances always observe the same underlying truth), so a caller (Task 6/7's cmd/lmm/tui.go) can call both with the game/profile it already resolved once, without re-deriving anything.
type DataProvider ¶
type DataProvider interface {
// Overview returns the dashboard summary and installed-mod rows from a
// single underlying fetch.
Overview(ctx context.Context) (Summary, []ModItem, error)
Profiles(ctx context.Context) ([]ProfileItem, error)
// Sources lists the game's configured real source IDs, sorted. The TUI
// prepends the all-sources sentinel ("") ahead of these (see
// newSearchModel); the CLI instead defaults to an aggregate search
// across all of them when --source is omitted (see doSearch in
// cmd/lmm/search.go).
Sources() []string
// SourceInfos lists every source registered with the service (built-in
// and user-defined), sorted by ID, for the read-only Sources screen. See
// SourceInfo's doc comment for how this differs from Sources.
SourceInfos() []SourceInfo
// Search queries one source, or every one of the game's configured
// sources when source is "" (the documented all-sources sentinel).
Search(ctx context.Context, source, query string, page int) (SearchPage, error)
}
DataProvider is the narrow, read-only boundary between the TUI and app data. Implementations must be safe to call from a Bubble Tea command goroutine.
func NewCoreProvider ¶
NewCoreProvider returns a DataProvider backed by the real app service for one game/profile pair.
func NewPrototypeProvider ¶
func NewPrototypeProvider() DataProvider
NewPrototypeProvider returns the side-effect-free demo DataProvider used by --prototype mode and tests. The returned value also implements ActionProvider (see actions_provider.go's prototypeProvider methods): a caller that needs both roles for one demo session should type-assert the single returned value (`provider.(ActionProvider)`) rather than calling this constructor twice, since each call seeds an independent in-memory dataset - two calls would silently diverge instead of sharing state.
type InstallPlanView ¶ added in v1.12.0
type InstallPlanView struct {
Name, Version, Source string
Files []string // display labels of the file(s) that would be downloaded
Dependencies []string // display names of resolved, not-yet-installed dependencies that would also install
Conflicts []string // "path (owned by <mod-id>)", one per conflicting file
MissingDependencies []string // "sourceID:modID" refs that couldn't be resolved - warn, don't block
CycleWarning bool // a circular dependency was found among Dependencies; install order is best-effort
Reinstall bool // item is already installed - applying replaces it rather than installing fresh
SizeLabel string // "12.3 MiB", or "size unknown" when no selected file declares a size
}
InstallPlanView is the render model for the install confirmation modal, mapped from core.InstallPlan (see coreProvider's installPlanView) or computed directly from prototype demo data - the install-modal analog of SwitchPlanView.
type KeyMap ¶
type KeyMap struct {
Quit key.Binding
Help key.Binding
NextScreen key.Binding
PrevScreen key.Binding
Up key.Binding
Down key.Binding
Search key.Binding
SearchScreen key.Binding
Dashboard key.Binding
InstalledMods key.Binding
Profiles key.Binding
Sources key.Binding
Select key.Binding
Submit key.Binding
Blur key.Binding
NextPage key.Binding
PrevPage key.Binding
CycleSource key.Binding
ConfirmAction key.Binding
CancelAction key.Binding
// ToggleEnable, Uninstall, and Deploy are Phase 5a's Installed
// Mods/Dashboard mutation bindings (see mutations.go). Profile switch
// deliberately has no binding of its own here - it reuses Select
// ("enter"), dispatched by screen in updateKey.
ToggleEnable key.Binding
Uninstall key.Binding
Deploy key.Binding
// Install is Phase 5b's install-from-search binding (see mutations.go's
// installSelectedSearchResult): it only fires on ScreenSearch with the
// input blurred and a result selected - a focused input swallows "i" as
// a typed character (see updateKey's focused-input branch, which runs
// before this ever reaches the outer switch).
Install key.Binding
// CheckUpdates is Phase 5b's check/apply-updates binding (see
// mutations.go's checkForUpdates): fires on ScreenDashboard and
// ScreenInstalledMods.
CheckUpdates key.Binding
}
KeyMap documents the TUI keyboard contract.
func DefaultKeyMap ¶
func DefaultKeyMap() KeyMap
DefaultKeyMap returns the shared key bindings shown in help and used by tests.
type ModItem ¶
type ModItem struct {
ID string
Name string
Author string
Version string
Source string
Status string
Summary string
Downloads int64
Endorsements int64
HasEndorsements bool
}
ModItem is one renderable mod row. ID, together with Source, fully addresses the mod for core mutations keyed on (sourceID, modID) - see ActionProvider.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the root Bubble Tea model for the lmm TUI.
func NewPrototypeModel ¶
NewPrototypeModel creates a side-effect-free TUI model backed by fake data. Provider and Actions are wired from the SAME prototypeProvider instance (see NewPrototypeProvider's doc comment), so actions confirmed through the returned Model are visible in its own subsequent reads — whatever the caller passed in either field is discarded.
func (Model) CurrentScreen ¶
CurrentScreen exposes the selected screen for tests.
func (Model) HelpVisible ¶
HelpVisible exposes help overlay state for tests.
func (Model) SelectedIndex ¶
SelectedIndex exposes the selected row for tests.
type Options ¶
type Options struct {
Theme string
Provider DataProvider
// Actions is the write-side ActionProvider seam (see actions_provider.go).
// Optional: a nil Actions means no mutation can be confirmed through
// promptAction/buildAction, which is fine for tests that only exercise
// the read-only DataProvider surface.
Actions ActionProvider
// Ctx seeds Model.ctx; see that field for why the context is stored
// rather than threaded as a parameter.
Ctx context.Context
}
Options configures the TUI app.
type ProfileItem ¶
ProfileItem is one renderable profile row.
type SearchPage ¶ added in v1.5.0
type SearchPage struct {
Results []ModItem
Query string
Source string
Page int // 0-based
PageSize int
TotalCount int // 0 if the source doesn't report totals
// Warnings holds per-source failures in all-sources mode, already
// formatted for display (e.g. "<sourceID>: <err>"). Empty for
// single-source searches.
Warnings []string
}
SearchPage is one page of search results for one source/query.
type SourceInfo ¶ added in v1.10.0
type SourceInfo struct {
ID string
Name string
Type string // "built-in", "directory", "manifest", or "api"
Auth string // "yes", "no", or "n/a" (source has no auth capability)
Capabilities string // compact list, e.g. "search,updates"
}
SourceInfo is one renderable source-registry row, mirroring the columns of `lmm source list` (cmd/lmm/source.go) minus its Error column: the Sources screen only lists sources that are actually REGISTERED with the service. Source-definition load failures (a malformed YAML file, an ID collision) never produce a registered source, so they have no row here and remain a CLI-only diagnostic (`lmm source list` / `lmm source validate`).
type Summary ¶
type Summary struct {
GameName string
ProfileName string
Installed int
Enabled int
Updates int // -1 = unknown (no update check has run)
Conflicts int // -1 = unknown
}
Summary is the dashboard header data.
type SwitchPlanView ¶ added in v1.11.0
type SwitchPlanView struct {
From, To string
Enable []string // mod names to enable
Disable []string // mod names to disable
NeedsDownloads []string // mod refs requiring download - ApplyProfileSwitch downloads and installs these itself (Phase 5b Task 4; see its doc comment), streaming progress the same way ApplyInstall/ApplyUpdate do
NoChanges bool
AlreadyActive bool
}
SwitchPlanView is the render model for the profile-switch confirmation modal, mapped from core.SwitchPlan (see coreProvider's switchPlanView) or computed directly from prototype demo data.
type UpdateItem ¶ added in v1.12.0
UpdateItem is one available update, as reported by CheckUpdates and consumed by ApplyUpdate.
type UpdatesView ¶ added in v1.12.0
type UpdatesView struct {
Updates []UpdateItem
Warnings []string
}
UpdatesView is CheckUpdates' result: the available updates plus any non-fatal per-source diagnostics (partial results still populate Updates - see coreProvider.CheckUpdates' doc comment).