package tui import ( "strings" "github.com/charmbracelet/lipgloss" ) // mascot is Codey: a gopher, because this is Go, wearing the two big eyes the // half-block grid can just about afford. // // It is drawn with half-blocks from the box-drawing range, so it needs no // patched font and degrades to something recognisable in a plain xterm. Every // row is eight cells wide — the wizard assembles it a row at a time and the // splash lays it out in a column, so a ragged row would show up as a wobble in // both. var mascot = []string{ "▄██████▄", "█ ██ █", "███▀▀███", " ▀█▀▀█▀ ", } const mascotGap = " " // splash is the welcome block. It goes into the scrollback rather than into // fixed chrome, so it scrolls away once there is real work to look at instead // of permanently taxing four rows of a small terminal. // // On a narrow terminal the mascot is dropped rather than sliced: half a mascot // reads as a rendering bug, where the three text lines alone read as a choice. func splash(o Options, width int) string { name := styHeading.Render("codey") if o.Version != "" { name += " " + styDim.Render(o.Version) } lines := []string{ name, styDim.Render(prettyModel(o.Client.Model()) + " · " + endpointLabel(o.Client)), styDim.Render(shortenHome(o.Root)), } // A fourth line, for the four things there is no other way to find out. // The mascot is four rows tall and the text was three, so this costs no // height at all on a terminal wide enough to show it — and on one that is // not, a half-sentence of hints would be worse than none, so it is dropped // whole rather than truncated. if width >= artWidth()+minSplashHints { lines = append(lines, styFaint.Render(splashHints)) } // The mascot is dropped only when the terminal cannot hold it beside a // readable amount of text. It is measured against a minimum rather than // against the longest line, or a deeply nested working directory would // silently cost you the whole welcome block. art := mascot if width < artWidth()+minSplashText { art = nil } var b strings.Builder for i := 0; i < maxInt(len(art), len(lines)); i++ { var line string if i < len(art) { line = styCoral.Render(art[i]) + mascotGap } if i < len(lines) { line += lines[i] } b.WriteString(truncateStyled(line, maxInt(1, width)) + "\n") } return b.String() } // minSplashText is how much room the text beside the mascot needs before the // mascot stops being worth its columns. const minSplashText = 24 // splashHints is the one line a first run needs: how to ask, where the // commands are, how to get a shell, and how to get back what you typed last // time. Everything else is in /help, which this line is mostly there to point // at. const splashHints = "/help · ↑ earlier prompts · ! shell · shift+tab approvals" // minSplashHints is how much room the hints need beside the mascot. Measured // from the string rather than guessed at, so editing the line cannot quietly // start truncating it. var minSplashHints = lipgloss.Width(splashHints) func artWidth() int { return lipgloss.Width(mascot[1]) + lipgloss.Width(mascotGap) }