render

package
v0.0.12 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FormatClock

func FormatClock(ts int32) string

FormatClock is the thread grid's time column: bare wall-clock, always five cells, no date part. The grid puts the date in a day divider instead, so repeating it on every row would only cost body width.

func FormatDayLabel

func FormatDayLabel(ts int32) string

FormatDayLabel is the label of a thread grid day divider. It is upper case because a divider is a rule with a word set into it, not a sentence.

The year is dropped within the current year: the divider's job is to say which day the messages under it belong to, and "12 AUG" answers that for anything recent while "12 AUG 2024" is what you need once it does not.

func FormatLastSeen

func FormatLastSeen(ts int32) string

FormatLastSeen formats a user's last seen timestamp.

func FormatRelativeShort

func FormatRelativeShort(ts int32) string

FormatRelativeShort is a relative time in the smallest space that still says something: "now", "4m", "4h", "yd", "2d", or a date once weeks have passed.

The rail's right-hand field is four cells and the chat list's is five. "4h ago" does not fit beside a name, and the "ago" is the half that carries no information — a relative time is already relative.

Hours give way to days at the DAY boundary, not at twenty-four hours. "23h" for something sent at nine last night is arithmetic; what the reader wants to know is whether it happened today, and a message from yesterday evening reading "14h" while one from this morning reads "6h" puts them on the same scale when the useful distinction is the night between them.

func FormatRelativeTime

func FormatRelativeTime(ts int32) string

FormatRelativeTime returns a relative time string (e.g., "2m ago").

func FormatTimestamp

func FormatTimestamp(ts int32) string

FormatTimestamp formats a Unix timestamp for display.

func FormatTimestampSmart

func FormatTimestampSmart(ts int32) string

FormatTimestampSmart formats a Unix timestamp using a compact, date-aware form suitable for lists (e.g. the chat list) where a full timestamp on every row would be redundant: messages from today show only the time, messages from the last 6 calendar days show a short weekday plus time, and anything older falls back to an ISO date.

func Now

func Now() time.Time

Now is the instant the renderer measures against: the real clock, unless a test has pinned one.

func PinClock

func PinClock(t time.Time) (restore func())

PinClock fixes the renderer's clock at t and returns the function that restores the previous one. Callers must restore it — a leaked pin makes every later test in the process render at somebody else's instant.

func PinClockFunc

func PinClockFunc(c clock) (restore func())

PinClockFunc is PinClock with a moving clock, for the tests that need one instant per call rather than one for the whole test.

func RenderInline

func RenderInline(ft *telegram.FormattedText, roles theme.Roles, o textOpts) string

RenderInline styles a whole formatted text with the semantic palette, and with OSC 8 hyperlinks when o.links says the terminal has them.

The hyperlinks were absent through phases 4 to 8 for a reason that turned out to be smaller than it looked: ansi.Wrap breaks a line between a link's opening and closing sequences and repairs neither, so the rest of that row — its padding and the panel rule beside it — becomes part of the link. The design record concluded that fixing it meant owning a grapheme-aware wrapper, because reopening a link means knowing which runes belong to it after wrapping. It does not: the URI is carried in the opening sequence, so cell.OpenLink can recover it from the wrapped line the same way OpenStyle recovers an SGR run. See docs/tui-2.0.md, divergence 14.

func RenderText

func RenderText(ft *telegram.FormattedText, roles theme.Roles, width int) []string

RenderText lays formatted text out as body lines, exactly as a message body is drawn: blocks split out, entities styled, everything wrapped to width with each line closing its own styles.

It is exported for the composer's preview, which has to be drawn by the same code that draws received messages. A preview rendered by a second implementation is a preview that can disagree with what arrives, and being trusted is the entire purpose of it.

No hyperlinks and no revealed spoilers: this is what the text WILL be, and a clickable link in a draft is an invitation to click a thing that has not been sent yet.

func SameDay

func SameDay(a, b int32) bool

SameDay reports whether two Unix timestamps fall on the same local calendar day. The thread grid uses it to decide where day dividers go.

func SenderName

func SenderName(msg *telegram.Message, s *store.Store) string

SenderName is the display name of a message's sender, resolved through the store. It is exported because the thread grid gives the sender its own column and therefore has to measure the name before drawing it.

Types

type BodyOptions

type BodyOptions struct {
	// Width is the body column's width in display cells.
	Width int

	// RevealSpoilers un-hides spoiler spans. True only for the message
	// under the cursor, and only after x.
	RevealSpoilers bool
}

BodyOptions is how a message is to be laid out for the thread grid.

type MessageRenderer

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

MessageRenderer turns message content into terminal lines. It holds the image renderer and its cache; everything else it does is stateless.

func NewMessageRenderer

func NewMessageRenderer() *MessageRenderer

func (*MessageRenderer) RenderBody

func (r *MessageRenderer) RenderBody(msg *telegram.Message, s *store.Store, opts BodyOptions) []string

RenderBody lays a message's content out for the TUI 2.0 thread grid's body column: one string per terminal line, with no frame of its own. The grid owns everything to the left of the body column, so this returns content and nothing else.

The result is never empty — a message with nothing renderable still occupies one line, because a zero-line message would make the scroll index disagree with what is on screen.

func (r *MessageRenderer) SetHyperlinks(on bool)

SetHyperlinks turns OSC 8 hyperlinks on the message body on or off. The caller resolves the policy and the terminal's capability together, once, so the renderer never has to.

func (*MessageRenderer) SetImageProtocol

func (r *MessageRenderer) SetImageProtocol(protocol media.Protocol, maxCols, maxRows int)

SetImageProtocol replaces the image renderer used for photo bubbles. Zero cols/rows fall back to the historical 50x25 bubble size.

func (*MessageRenderer) SetInlineImages

func (r *MessageRenderer) SetInlineImages(policy string)

SetInlineImages sets the resolved ui.inline_images policy: whether a photo is drawn as art or as a metadata card.

"never" is the setting that matters. A terminal whose image support was guessed wrong turns every photo into a screenful of garbage, and the user needs a way to say so that does not also turn off downloading.

func (*MessageRenderer) SetRoles

func (r *MessageRenderer) SetRoles(roles theme.Roles)

SetRoles supplies the TUI 2.0 semantic palette used for entity styling, code frames, quotes and media cards.

Jump to

Keyboard shortcuts

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