app

package
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 35 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArgSpec

type ArgSpec int

ArgSpec describes what a command does with the text after its name.

const (
	// ArgNone: the command takes no argument and rejects one rather than
	// silently ignoring it. Silently discarding input is how ":quit now"
	// becomes a bug report about a command that "sometimes does nothing".
	ArgNone ArgSpec = iota
	// ArgOptional: the argument changes behaviour but may be omitted.
	ArgOptional
	// ArgRequired: without it the command cannot run.
	ArgRequired
)

type AuthErrorMsg

type AuthErrorMsg struct {
	Err error
}

AuthErrorMsg is sent when the Telegram client fails during authentication.

type AuthStateChangedMsg

type AuthStateChangedMsg struct {
	State int
	Hint  string
}

AuthStateChangedMsg is sent from the authorizer callback.

type AuthenticatedMsg

type AuthenticatedMsg struct {
	UserId    int64
	FirstName string
	LastName  string
}

AuthenticatedMsg signals that authentication is complete.

type ClipboardPasteFailedMsg

type ClipboardPasteFailedMsg struct {
	Err error
}

ClipboardPasteFailedMsg reports why a clipboard paste produced nothing.

type ClipboardPastedMsg

type ClipboardPastedMsg struct {
	// ChatId is the chat that was active when the paste was requested. If
	// the active chat has changed by the time this message arrives, the
	// paste is discarded rather than installed into the wrong chat.
	ChatId  int64
	Path    string
	IsImage bool
}

ClipboardPastedMsg carries a clipboard image that has been spooled to disk and is ready to attach.

type Command

type Command struct {
	// Name is the command word, without the colon.
	Name string
	// Arg describes the argument, and Placeholder names it for display
	// (e.g. "<query>"). Placeholder must be empty when Arg is ArgNone.
	Arg         ArgSpec
	Placeholder string
	// Description is one line, shown in the palette.
	Description string
	// Key is the equivalent key binding shown right-aligned, so the palette
	// teaches the keymap rather than duplicating it. Empty when there is no
	// single key for the command.
	Key string
	// Run performs the command. It receives the model by value and returns
	// the updated model, matching how Update threads state everywhere else.
	// The returned string is a notice for the user; empty means silent.
	Run func(m Model, arg string) (Model, tea.Cmd, string)
}

Command is one entry in the registry.

A single typed table supplies everything about a command — its name, argument shape, description, key equivalent, and what it does — so the palette, the help card, and any future `:keymap` output all read from the same place and cannot drift apart. That is the whole reason this is a table rather than a switch in Update.

type ErrorMsg

type ErrorMsg struct {
	Err error
}

ErrorMsg carries an error to display.

type FocusChangedMsg

type FocusChangedMsg struct {
	Panel FocusPanel
}

FocusChangedMsg signals a focus panel change.

type FocusPanel

type FocusPanel int

FocusPanel identifies which UI panel has focus.

const (
	PanelChatList FocusPanel = iota
	PanelChatView
	PanelComposer
	PanelSearch
	PanelContacts
)

type InteractionMode

type InteractionMode int

InteractionMode is the app-level answer to one question: will the next printable key be typed as text, or acted on as a command?

TUI 2.0 makes that question answerable at a glance (docs/tui-2.0.md, "Mode integration", resolved by decision 3). The mode is **derived**, never stored: it is computed from focus, the composer's own editing state, and which overlay owns the keyboard. There is deliberately no mode field to set, because a second source of truth beside FocusPanel could contradict what the app actually does with a keystroke — and a badge that lies about that is worse than no badge.

const (
	// ModeNormal means printable keys act rather than type. It covers the
	// browsing panels, the overlays that navigate rather than collect text,
	// and — importantly — a vi composer that has returned to its command
	// state. In that last case the composer still owns its vi commands; the
	// badge is telling the truth when it says the next letter will not be
	// inserted.
	ModeNormal InteractionMode = iota
	// ModeInsert means printable keys are inserted as text: the composer
	// with an editor that will accept them, a text-collecting overlay, or
	// the auth form.
	ModeInsert
	// ModeCommand means the command palette owns input.
	ModeCommand
)

func (InteractionMode) String

func (m InteractionMode) String() string

type Model

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

func New

func New(cfg *config.Config, tg *telegram.Client, s *store.Store, authorizer *telegram.TUIAuthorizer) Model

func (Model) Init

func (m Model) Init() tea.Cmd

Init starts the chrome tick. Without it the top bar's clock would show the time of the last window resize for the rest of the session, and a transient notice would own the hint bar until something replaced it.

func (Model) Mode

func (m Model) Mode() InteractionMode

Mode reports the current interaction mode.

This is the single source the mode badge, the context-sensitive hint bar, and the palette's `:` routing must consult, so that all three agree with what Update actually does with a keystroke.

It is NOT a drop-in replacement for the existing focus checks in Update, and retrofitting it onto them would change behaviour: ModeNormal includes a vi composer in command state, so a guard written as "mode is NORMAL" would let `?` open the help overlay while the composer holds a draft, where today's "focus is not the composer" correctly does not. Decision 3 requires the badge to describe the existing key routing, not alter it.

func (Model) Update

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles one message and then reconciles the frame with whatever it did.

The reconciliation is here rather than at the end of the switch because the switch has sixty-five early returns, and a step that only runs when the code happens to fall out of the bottom is a step that runs for most messages and silently not for the ones that matter.

func (Model) View

func (m Model) View() tea.View

type ScreenState

type ScreenState int

ScreenState identifies the current top-level screen.

const (
	ScreenAuth ScreenState = iota
	ScreenLoading
	ScreenMain
)

type SendFailedMsg

type SendFailedMsg struct {
	Err        error
	ChatId     int64 // chat the send was for; restore only into that composer
	Attachment string
	AsPhoto    bool
}

SendFailedMsg reports a send that failed after the composer was already reset. It carries the attachment back so it can be restored for a retry instead of being lost with the spool file.

Jump to

Keyboard shortcuts

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