ui

package
v0.0.0-...-2e51cb2 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	Stdout    io.Writer = os.Stdout
	Stderr    io.Writer = os.Stderr
	DefaultUI           = Console{Stdout: Stdout, Stderr: Stderr}

	// Log is the global structured console logger used when the TUI is inactive.
	// It uses charmbracelet/log with custom lipgloss styles matching the TUI palette.
	Log *charmlog.Logger
)

Stdout / Stderr — direct os handles. termenv (used by lipgloss) detects the active output's capabilities and writes appropriate ANSI sequences, including on modern Windows terminals (10+, 2019+) which support VT processing natively. go-colorable is no longer required.

View Source
var DisplayProgress = true

DisplayProgress controls whether the TUI progress bar is shown. Set to false in tests to disable TUI output.

View Source
var Program *tea.Program

Program is the global tea.Program; goroutines call Program.Send() to deliver messages.

View Source
var Theme = theme{
	Phosphor: lipgloss.Color("#73E0FF"),
	Amber:    lipgloss.Color("#FFB75A"),
	Mint:     lipgloss.Color("#5EE6A1"),
	Magenta:  lipgloss.Color("#FF5478"),
	Steel:    lipgloss.Color("#5A6B85"),
	Slate:    lipgloss.Color("#3A475C"),
	Frost:    lipgloss.Color("#E8F1F8"),
	DeepCyan: lipgloss.Color("#1E7A99"),
}

Functions

func ConfirmRedownload

func ConfirmRedownload(filename string) bool

func DisplayProgressBar

func DisplayProgressBar() bool

DisplayProgressBar returns true when running in interactive TTY mode.

func Errorf

func Errorf(format string, a ...any) (n int, err error)

Errorf outputs error-level logs, routing to TUI when available.

func Errorln

func Errorln(a ...any) (n int, err error)

Errorln is the non-formatted error printer.

func IsTerminal

func IsTerminal(f *os.File) bool

IsTerminal checks if f is connected to a real TTY.

func NewExtractorModel

func NewExtractorModel(url string, onQuit func()) extractorModel

NewExtractorModel constructs the extractor-mode TUI model.

func NewProgram

func NewProgram(numConns int) *tea.Program

NewProgram creates and starts a new Bubble Tea program for the TUI.

func NewTUIModel

func NewTUIModel(numConns int, willVerify bool, batchCurrent, batchTotal int, onSkip, onQuit func()) tuiModel

NewTUIModel creates a new TUI model for the given number of connections. batchCurrent and batchTotal are 1-based; pass 0,0 when not in batch mode. onSkip is non-nil only in batch mode and is invoked when the user presses 's'. onQuit is invoked on 'q' / 'ctrl+c'; both default to no-ops if nil.

func NewTUIModelWithHistory

func NewTUIModelWithHistory(
	numConns int,
	willVerify bool,
	batchCurrent, batchTotal int,
	history []BatchItemSnapshot,
	onSkip, onQuit func(),
) tuiModel

NewTUIModelWithHistory is the variant that lets the caller seed the per-batch-item lifecycle record. Used by RunWithTUI when the parent batch loop has accumulated skip / fail / done history before this TUI session was started.

func PrintHelp

func PrintHelp()

func PrintVerifySummary

func PrintVerifySummary(ok bool, detail string)

PrintVerifySummary writes a styled one-line verify result to the terminal using charmbracelet/log (works after the TUI alt-screen has closed).

func Printf

func Printf(format string, a ...any) (n int, err error)

Printf outputs information-level logs, routing to TUI when available.

func ResumePrompt

func ResumePrompt(taskName string, downloaded, total int64) (bool, error)

ResumePrompt shows an animated TUI prompt asking whether to resume a partial download. Returns true if user wants to resume, false to start fresh.

func RunExtractorTUI

func RunExtractorTUI(opts ExtractorRunOptions, worker func(ExtractorSelector) error) error

RunExtractorTUI starts a Bubble Tea program using the extractor model and runs `worker` in a goroutine. The worker is expected to send Extractor* messages via the package-level Program handle. Mirrors the shape of RunWithTUI: when stdout isn't a TTY, the worker runs directly and TUI sends are no-ops (the package-level Program is nil).

`worker` is invoked with an ExtractorSelector that blocks until the user commits a format choice in the VCR's browsing mode. Workers that bypass the selector (live streams, no format table) simply don't call it. In the non-TTY fallback path the selector returns immediately with empty strings ("use defaults").

func RunWithTUI

func RunWithTUI(opts RunOptions, fn func() error) error

func ShowMessage

func ShowMessage(msgType MessageType, title, message string)

ShowMessage displays a styled message box and returns immediately.

func ThemeBox

func ThemeBox(border lipgloss.Color, width int) lipgloss.Style

Box renders a chrome-bordered panel in the carrier style. Used by the modem, mainframe, tape, vault, and message-box primitives so they share identical chrome.

func Warnf

func Warnf(format string, a ...any) (n int, err error)

Warnf outputs warning-level logs, routing to TUI when available.

Types

type BatchFinishedMsg

type BatchFinishedMsg struct {
	Done    int
	Failed  int
	Skipped int
	Aborted int
}

BatchFinishedMsg signals all items have run; render the final summary frame and auto-quit.

type BatchItemBeginMsg

type BatchItemBeginMsg struct {
	Index    int // 0-based index into the batch
	URL      string
	FileName string
}

BatchItemBeginMsg signals the start of a new item inside a persistent batch TUI program. The model resets per-item state but keeps the SAN cabinet, history, and program alive (no alt-screen toggling).

type BatchItemEndMsg

type BatchItemEndMsg struct {
	Index  int
	Status BatchItemStatus
	Reason string
}

BatchItemEndMsg signals an item finished (success / fail / skip / abort). Updates the SAN bay status without quitting the program.

type BatchItemResult

type BatchItemResult struct {
	Status BatchItemStatus
	Reason string
}

type BatchItemSnapshot

type BatchItemSnapshot struct {
	Label  string
	Status BatchItemStatus
}

type BatchItemStatus

type BatchItemStatus int
const (
	BatchItemQueued BatchItemStatus = iota
	BatchItemDone
	BatchItemSkipped
	BatchItemFailed
	BatchItemAborted
)

type BatchRunOptions

type BatchRunOptions struct {
	Ctx           context.Context
	NumConns      int
	WillVerify    bool
	Items         []BatchItemSnapshot
	URLs          []string
	OnQuit        func()
	OnSkipCurrent func()
}

BatchRunOptions configures a persistent batch TUI session.

type BatchSummary

type BatchSummary struct {
	Done    int
	Failed  int
	Skipped int
	Aborted int
}

BatchSummary aggregates the tally over the whole batch.

func RunBatch

func RunBatch(opts BatchRunOptions, runItem func(idx int) BatchItemResult) (BatchSummary, error)

type CassetteItem

type CassetteItem struct {
	URL        string
	Title      string        // resolved from yt-dlp metadata; empty until probed
	Channel    string        // populates the channel-tint sticker chip
	Duration   time.Duration // 00:00 until probed
	Resolution string        // "1080p60" — only on lush tier
	Status     CassetteStatus
	Err        string // populated on failure for the end-of-batch summary
}

CassetteItem is one row of the shelf — everything renderable about a single URL in the batch. Field renames cascade nowhere: the shelf is the only consumer.

type CassetteShelf

type CassetteShelf struct {
	// contains filtered or unexported fields
}

CassetteShelf is the widget. Built once at batch start, mutated via the setter methods below as the orchestrator advances.

func NewCassetteShelf

func NewCassetteShelf(urls []string) *CassetteShelf

NewCassetteShelf seeds the widget from a URL list. Labels read as "tape NN" until probes resolve real titles.

func (*CassetteShelf) Items

func (s *CassetteShelf) Items() []CassetteItem

Items returns a defensive copy so callers can iterate without racing concurrent mutations. Used by the end-of-batch summary.

func (*CassetteShelf) Len

func (s *CassetteShelf) Len() int

Len reports how many tapes are on the shelf.

func (*CassetteShelf) SetActive

func (s *CassetteShelf) SetActive(i int)

SetActive marks one cassette as the live tape. Pass -1 to indicate no tape is currently in the deck (between items, or post-batch).

func (*CassetteShelf) SetMeta

func (s *CassetteShelf) SetMeta(i int, title, channel, resolution string, dur time.Duration)

SetMeta fills in metadata that arrives from yt-dlp's probe. Empty fields on the incoming item are ignored so partial probes don't blank out previously-set values.

func (*CassetteShelf) SetStatus

func (s *CassetteShelf) SetStatus(i int, st CassetteStatus, errMsg string)

SetStatus updates one cassette's lifecycle state. errMsg is recorded only when the new status is CassetteFailed.

func (*CassetteShelf) Tick

func (s *CassetteShelf) Tick()

Tick advances the lift animation for the active cassette and the reel-rotation frame counter. Drives both the "tape pulls out of the shelf" effect and the spinning-reel illusion.

func (*CassetteShelf) View

func (s *CassetteShelf) View(termWidth int) string

View renders the shelf at the requested terminal width. Returns at most cassetteShelfRows lines. The layout is computed every call so resizes (WindowSizeMsg) reflow without ceremony.

type CassetteStatus

type CassetteStatus int

CassetteStatus is the lifecycle state of one tape on the shelf.

const (
	CassetteQueued CassetteStatus = iota
	CassetteProbing
	CassetteReady // probe done, waiting for the deck to swing to it
	CassetteLoading
	CassettePlaying
	CassetteMuxing
	CassetteDone
	CassetteSkipped
	CassetteFailed
)

type Console

type Console struct {
	Stdout io.Writer
	Stderr io.Writer
}

Console is the non-TUI implementation of UI.

func (Console) Errorf

func (c Console) Errorf(format string, a ...any) (n int, err error)

func (Console) Errorln

func (c Console) Errorln(a ...any) (n int, err error)

func (Console) Printf

func (c Console) Printf(format string, a ...any) (n int, err error)

func (Console) Println

func (c Console) Println(a ...any) (n int, err error)

type DownloadDoneMsg

type DownloadDoneMsg struct{}

DownloadDoneMsg signals the entire pipeline (download + join + optional verify) finished.

type DownloadErrorMsg

type DownloadErrorMsg struct{ Err error }

DownloadErrorMsg signals a fatal download error.

type DownloadStartMsg

type DownloadStartMsg struct {
	URL      string
	FileName string
	Size     int64
	NumParts int
	IPs      []string
}

DownloadStartMsg is sent once download metadata is known.

type ExtractorDoneMsg

type ExtractorDoneMsg struct{}

ExtractorDoneMsg signals success — auto-quit countdown begins.

type ExtractorErrorMsg

type ExtractorErrorMsg struct{ Err error }

ExtractorErrorMsg signals a fatal error in the extractor pipeline.

type ExtractorFormat

type ExtractorFormat struct {
	ID         string
	Ext        string
	Resolution string
	Height     int
	FPS        float64
	VCodec     string
	ACodec     string
	TBR        float64
	ABR        float64
	Filesize   int64
	Note       string
	HasVideo   bool
	HasAudio   bool
}

ExtractorFormat mirrors extractor.Format inside the ui package so the renderer doesn't pull a dependency cycle. Populated via the ExtractorFormatsMsg pipeline.

type ExtractorFormatsMsg

type ExtractorFormatsMsg struct {
	Video      []ExtractorFormat
	Audio      []ExtractorFormat
	Containers []string
	IsLive     bool // live streams always skip the selector
}

ExtractorFormatsMsg seeds the VCR's browsing-mode selector with the format table parsed from yt-dlp's -J output. Sent immediately after the metadata message during the probe → select handshake.

An empty Video slice means there are no separately-selectable video streams; the model then skips the browser entirely and falls through to yt-dlp's default format spec.

type ExtractorLogMsg

type ExtractorLogMsg struct {
	Level string // "info" | "warn" | "error"
	Text  string
}

ExtractorLogMsg adds a line to the on-screen log strip.

type ExtractorMetaMsg

type ExtractorMetaMsg struct {
	Title      string
	Channel    string
	Duration   time.Duration
	Resolution string
	FPS        float64
	VCodec     string
	ACodec     string
	Container  string
	HasAudio   bool
	OutputFile string // hint — actual path resolved post-merge
}

ExtractorMetaMsg seeds the VCR header with metadata from yt-dlp -J.

type ExtractorOutputMsg

type ExtractorOutputMsg struct{ Path string }

ExtractorOutputMsg surfaces yt-dlp's resolved output path post-merge.

type ExtractorPhaseMsg

type ExtractorPhaseMsg struct {
	Phase string // "downloading" | "muxing" | "done" | "error"
}

ExtractorPhaseMsg switches the active panel: VCR vs Mixer vs done.

type ExtractorProgressMsg

type ExtractorProgressMsg struct {
	Percent    float64 // 0..100
	Downloaded int64
	Total      int64
	SpeedBPS   float64
	ETA        time.Duration
	Fragment   int
	FragmentN  int
}

ExtractorProgressMsg pushes one progress update from yt-dlp.

type ExtractorResetDeckMsg

type ExtractorResetDeckMsg struct{}

ExtractorResetDeckMsg clears the deck (progress, output path, logs) between batch items so the next tape starts fresh. The VCR returns to standby until the next ExtractorMetaMsg arrives.

type ExtractorRunOptions

type ExtractorRunOptions struct {
	Ctx    context.Context
	URL    string
	OnQuit func()
}

ExtractorRunOptions configures RunExtractorTUI.

type ExtractorSelectionMsg

type ExtractorSelectionMsg struct {
	Spec      string
	Container string

	HeightCeiling int
	FPSFloor      int
	VCodec        string
	ABRCeiling    int
	Progressive   bool
}

ExtractorSelectionMsg is internal — the model emits it when the user commits a format choice in browsing mode. The runner forwards the payload to the worker goroutine via a buffered channel.

In addition to the exact format spec, the message carries adaptive descriptors (height ceiling, codec hint, audio bitrate ceiling). The batch pipeline uses those to build a yt-dlp filter expression that survives videos that lack the originally-picked format IDs.

type ExtractorSelector

type ExtractorSelector func(ctx context.Context) (ExtractorSelectionMsg, error)

ExtractorSelector blocks until the user commits a format selection from the VCR's browsing mode, or until ctx is cancelled. Returns the full ExtractorSelectionMsg so callers can pull both the exact spec (for single-URL runs) and the adaptive descriptors (for batch FormatAll caching). A zero-value selection means "use the default pipeline" — happens when the source has no selectable formats or the user dismissed without picking.

type ExtractorShelfActiveMsg

type ExtractorShelfActiveMsg struct {
	Index int
}

ExtractorShelfActiveMsg marks one cassette as the currently-playing tape. Pass Index=-1 between items or at end-of-batch.

type ExtractorShelfMetaMsg

type ExtractorShelfMetaMsg struct {
	Index      int
	Title      string
	Channel    string
	Resolution string
	Duration   time.Duration
}

ExtractorShelfMetaMsg fills in the metadata for one cassette as probes resolve. Fired by the eager probe pool so spine labels populate ahead of the deck reaching that tape.

type ExtractorShelfSeedMsg

type ExtractorShelfSeedMsg struct {
	URLs []string
}

ExtractorShelfSeedMsg installs the cassette shelf at batch start. One CassetteItem per URL. Sent before any per-tape activity so the shelf is visible from the first frame.

type ExtractorShelfStatusMsg

type ExtractorShelfStatusMsg struct {
	Index  int
	Status CassetteStatus
	Err    string
}

ExtractorShelfStatusMsg updates one cassette's lifecycle state.

type ExtractorURLMsg

type ExtractorURLMsg struct{ URL string }

ExtractorURLMsg updates the "source" line shown above the shelf when the active tape changes mid-batch. In single-URL mode the URL is fixed at construction time and this message is never sent.

type JoinDoneMsg

type JoinDoneMsg struct{}

JoinDoneMsg signals joining finished.

type JoinProgressMsg

type JoinProgressMsg struct{ Current int }

JoinProgressMsg carries joining progress.

type JoinStartMsg

type JoinStartMsg struct{ Total int }

JoinStartMsg signals the file-joining phase started.

type LogMsg

type LogMsg struct {
	Level string // "info" | "warn" | "error"
	Text  string
}

LogMsg adds an entry to the on-screen log panel.

type MessageType

type MessageType int

MessageBox renders a styled message box that fits the modem theme.

const (
	MessageInfo MessageType = iota
	MessageWarning
	MessageError
	MessageSuccess
)

type MixerAnimation

type MixerAnimation struct {
	// contains filtered or unexported fields
}

MixerAnimation — analog-mixer themed visualization for the post-processing (ffmpeg mux) phase. Even though we don't get true progress from yt-dlp's internal ffmpeg call, we drive a believable rolling animation: VU meters on V/A channel strips, a sweeping EQ graph, motorized fader catch-up, and a master meter that pegs as the mux finishes.

func NewMixer

func NewMixer() MixerAnimation

NewMixer builds a fresh idle mixer animation.

func (*MixerAnimation) Frame

func (m *MixerAnimation) Frame() int

func (*MixerAnimation) Mode

func (m *MixerAnimation) Mode() MixerMode

func (*MixerAnimation) SetMeta

func (m *MixerAnimation) SetMeta(meta MixerMeta)

func (*MixerAnimation) SetMode

func (m *MixerAnimation) SetMode(mode MixerMode)

func (*MixerAnimation) Tick

func (m *MixerAnimation) Tick()

Tick advances the animation. Call once per render frame.

func (MixerAnimation) View

func (m MixerAnimation) View() string

View renders the mixer panel.

type MixerMeta

type MixerMeta struct {
	VideoCodec string // tag for video channel strip
	AudioCodec string // tag for audio channel strip
	Container  string // master section "BUS OUT" caption (mp4 / mkv / webm)
	OutputFile string // shown on the master strip
	Bitrate    string // optional
}

MixerMeta — labels shown on the channel strips and master section.

type MixerMode

type MixerMode int

MixerMode is the mixer panel's operational state.

const (
	MixerIdle MixerMode = iota
	MixerMixing
	MixerDone
	MixerError
)

type PartDoneMsg

type PartDoneMsg struct{ Index int }

PartDoneMsg signals a chunk finished downloading successfully.

type PartProgressMsg

type PartProgressMsg struct {
	Index      int
	Downloaded int64
	Total      int64
}

PartProgressMsg carries incremental progress for one chunk.

type RunOptions

type RunOptions struct {
	// Ctx is observed for external cancellation (e.g. SIGINT routed through
	// signal.NotifyContext at main).  When Ctx is cancelled, RunWithTUI
	// surfaces a "stopping…" overlay and waits for fn to drain.
	Ctx context.Context
	// OnSkip is called when the user presses 's' (batch mode only).
	OnSkip func()
	// OnQuit is called when the user presses 'q' / 'ctrl+c'.
	OnQuit       func()
	NumConns     int
	WillVerify   bool
	BatchCurrent int
	BatchTotal   int
	BatchHistory []BatchItemSnapshot
}

RunOptions configures a TUI session.

type SkippingMsg

type SkippingMsg struct{}

SkippingMsg overlays a "skipping" panel for the current batch item.

type StoppingMsg

type StoppingMsg struct {
	// Reason renders inside the stopping panel; e.g. "Aborted by user".
	Reason string
}

StoppingMsg is sent when an external cancellation (e.g. SIGINT routed through signal.NotifyContext) has been requested. The TUI overlays a "stopping" panel until the worker goroutine reports completion.

type UI

type UI interface {
	Printf(format string, a ...any) (n int, err error)
	Println(a ...any) (n int, err error)
	Errorf(format string, a ...any) (n int, err error)
	Errorln(a ...any) (n int, err error)
}

UI represents simple IO output.

type VCRAnimation

type VCRAnimation struct {
	// contains filtered or unexported fields
}

VCRAnimation drives the on-screen VCR. Tick() advances the animation frame; Update() pushes new download progress. The renderer is pure.

func NewVCR

func NewVCR() VCRAnimation

NewVCR builds a fresh, idle VCR animation.

func (VCRAnimation) CurrentAudio

func (v VCRAnimation) CurrentAudio() (ExtractorFormat, bool)

func (VCRAnimation) CurrentContainer

func (v VCRAnimation) CurrentContainer() string

func (VCRAnimation) CurrentVideo

func (v VCRAnimation) CurrentVideo() (ExtractorFormat, bool)

CurrentVideo / CurrentAudio / CurrentContainer return the selected rocker positions. Returned booleans are false when the relevant list is empty (e.g. audio-only sources have no separate audio track).

func (*VCRAnimation) CycleAudio

func (v *VCRAnimation) CycleAudio(step int)

func (*VCRAnimation) CycleContainer

func (v *VCRAnimation) CycleContainer(step int)

func (*VCRAnimation) CycleVideo

func (v *VCRAnimation) CycleVideo(step int)

CycleVideo / CycleAudio / CycleContainer advance (or rewind, with a negative step) the corresponding selector by one. Indices wrap so the rocker switch reads as endless rather than bouncing off endstops.

func (*VCRAnimation) Frame

func (v *VCRAnimation) Frame() int

func (VCRAnimation) HasFormats

func (v VCRAnimation) HasFormats() bool

HasFormats reports whether the browsing UI has anything to show.

func (*VCRAnimation) Mode

func (v *VCRAnimation) Mode() VCRMode

func (VCRAnimation) Selection

func (v VCRAnimation) Selection() ExtractorSelectionMsg

Selection builds the full format selection (exact spec + container + adaptive descriptors) from the current rocker positions. When the chosen video format is progressive (carries its own audio), the audio selector is ignored. The adaptive descriptors let downstream callers translate the pick into a yt-dlp filter expression that survives sources lacking the exact format IDs.

func (*VCRAnimation) SetFormats

func (v *VCRAnimation) SetFormats(video, audio []ExtractorFormat, containers []string)

SetFormats seeds the browsing-mode selector with the format table emitted by the extractor. Defaults are highest-quality video, first audio track, mp4 container — matching yt-dlp's bv*+ba/b heuristic so "just hit enter" produces the pre-selector behaviour.

func (*VCRAnimation) SetMeta

func (v *VCRAnimation) SetMeta(m VCRMeta)

func (*VCRAnimation) SetMode

func (v *VCRAnimation) SetMode(m VCRMode)

func (*VCRAnimation) Tick

func (v *VCRAnimation) Tick()

Tick advances the animation. Call once per render frame (~60 Hz).

func (*VCRAnimation) Update

func (v *VCRAnimation) Update(pct float64, downloaded, total int64, speedBPS float64, eta time.Duration, fragment, fragmentN int)

Update pushes new download stats. Called whenever the extractor emits a DownloadProgress event.

func (VCRAnimation) View

func (v VCRAnimation) View() string

View renders the entire VCR panel as a single string.

type VCRMeta

type VCRMeta struct {
	Title       string
	Channel     string
	Duration    time.Duration
	Resolution  string
	FPS         float64
	VCodec      string
	ACodec      string
	Container   string
	HasAudio    bool   // controls whether the AUDIO meter is shown
	StreamLabel string // "VIDEO" / "AUDIO" / "" — drives front-LED
}

VCRMeta — the metadata strip shown above the tape window. All fields are optional; absent values render as "—".

type VCRMode

type VCRMode int

VCRMode is the operational state of the VCR panel. Mirrors the extractor.Phase but stays in the ui package so the renderer never imports extractor.

const (
	VCRStandby   VCRMode = iota // pre-recording, "tape inserted" state
	VCRBrowsing                 // probe complete; user is picking a tape
	VCRRecording                // [download] phase active
	VCREjecting                 // post-record cooldown (between phases)
	VCRError
)

type VerifyDetails

type VerifyDetails struct {
	SignedBy    string // user id, e.g. "Linus Torvalds <torvalds@kernel.org>"
	KeyID       string // long key id, e.g. "ABCDEF1234567890"
	Fingerprint string // 40-hex fingerprint with spaces every 4 chars
	SignedAt    string // signature timestamp string
	Verdict     string // short verdict label rendered in the verdict row
	Raw         string // raw gpg output, kept for the "details" pane
}

func ParseGPGOutput

func ParseGPGOutput(output string) VerifyDetails

ParseGPGOutput extracts structured fields from `gpg --verify` output so the vault's detail rows show signing identity instead of raw stderr.

Recognised lines (gpg ≥ 2.2):

gpg: Signature made Mon Jan  1 12:00:00 2024 UTC
gpg:                using RSA key ABCDEF1234567890ABCDEF1234567890DEADBEEF
gpg: Good signature from "Linus Torvalds <torvalds@kernel.org>" [unknown]
Primary key fingerprint: ABCD 1234 EF56 7890 ABCD 1234 EF56 7890 ABCD 1234
gpg: BAD signature from "Mallory <mallory@example.com>"

type VerifyDoneMsg

type VerifyDoneMsg struct {
	OK     bool
	Detail string // gpg output excerpt
}

VerifyDoneMsg signals GPG verification has completed.

type VerifyStartMsg

type VerifyStartMsg struct{}

VerifyStartMsg signals GPG signature verification has begun.

Jump to

Keyboard shortcuts

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