package tui
import (
"fmt"
"net/url"
"os"
"strings"
"harness/internal/llm"
)
// human renders a token count the way a status bar wants to read it.
func human(n int) string {
switch {
case n >= 1_000_000:
return fmt.Sprintf("%.1fM", float64(n)/1e6)
case n >= 1_000:
return fmt.Sprintf("%.1fk", float64(n)/1e3)
}
return fmt.Sprint(n)
}
// prettyModel names a model the way a person does. The transform itself lives
// in llm, next to the ids it is about, so the wizard's list and the status bar
// cannot disagree about what a model is called.
func prettyModel(id string) string { return llm.PrettyModel(id) }
// endpointLabel names where the prompts are going. The default endpoint gets
// a short name; anything else shows its host, because "somewhere that is not
// Anthropic" is the single most important thing the header can say.
func endpointLabel(c *llm.Client) string {
if c == nil {
return ""
}
if c.IsDefaultEndpoint() {
return "anthropic"
}
if u, err := url.Parse(c.BaseURL); err == nil && u.Host != "" {
return u.Host
}
return c.BaseURL
}
// camel renders a snake_case tool name as the transcript shows it: read_file
// becomes ReadFile. It is a display transform only — approvals and errors
// still quote the real name.
func camel(name string) string {
parts := strings.Split(name, "_")
for i, p := range parts {
if p == "" {
continue
}
parts[i] = strings.ToUpper(p[:1]) + p[1:]
}
return strings.Join(parts, "")
}
func maxInt(a, b int) int {
if a > b {
return a
}
return b
}
func minInt(a, b int) int {
if a < b {
return a
}
return b
}
// shortenHome writes a path the way a person says it. The working root is
// shown in the welcome block, where "~/Work/thing" carries the same
// information as the absolute path in a third of the columns.
func shortenHome(path string) string {
home, err := os.UserHomeDir()
if err != nil || home == "" || path == home {
return path
}
if strings.HasPrefix(path, home+string(os.PathSeparator)) {
return "~" + path[len(home):]
}
return path
}