Function bodies 209 total
components.Item.Render method · go · L53-L72 (20 LOC)src/internal/presentation/components/tui_item.go
func (i Item) Render(selected bool, labelWidth int, width int, spinnerFrame string) string {
switch i.Kind {
case KindHeader:
return renderSection(i.Label, width)
case KindNavigation:
return i.renderNavigation(selected, labelWidth)
case KindAction:
return i.renderAction(selected)
case KindToggle:
return i.renderToggle(selected, labelWidth, spinnerFrame)
case KindExpandable:
return i.renderExpandable(selected, labelWidth)
}
return ""
}components.Item.renderNavigation method · go · L79-L91 (13 LOC)src/internal/presentation/components/tui_item.go
func (i Item) renderNavigation(selected bool, labelWidth int) string {
prefix := i.buildPrefix(selected)
paddedLabel := i.Label
if labelWidth > 0 {
paddedLabel = fmt.Sprintf("%-*s", labelWidth, i.Label)
}
if selected {
return theme.Selected.Render(fmt.Sprintf("%s%s", prefix, paddedLabel)) + RenderDescription(i.Description)
}
return prefix + theme.Action.Render(paddedLabel) + RenderDescription(i.Description)
}components.Item.renderAction method · go · L93-L100 (8 LOC)src/internal/presentation/components/tui_item.go
func (i Item) renderAction(selected bool) string {
prefix := i.buildPrefix(selected)
style := theme.Normal
if selected {
style = theme.Selected
}
return style.Render(prefix + i.Label)
}components.Item.renderToggle method · go · L102-L141 (40 LOC)src/internal/presentation/components/tui_item.go
func (i Item) renderToggle(selected bool, labelWidth int, spinnerFrame string) string {
var statusBadge string
switch i.State {
case StateChecked:
statusBadge = BadgeOK()
case StateUnchecked:
statusBadge = BadgeError()
case StateLoading:
if spinnerFrame != "" {
statusBadge = theme.SpinnerStyle.Render(spinnerFrame)
} else {
statusBadge = theme.BadgeLoading.Render(theme.IconLoading)
}
default:
statusBadge = " "
}
prefix := i.buildPrefix(selected)
style := theme.Normal
if selected {
style = theme.Selected
}
paddedLabel := i.Label
if labelWidth > 0 {
paddedLabel = fmt.Sprintf("%-*s", labelWidth, i.Label)
}
// Status on the right: label description status
if i.Description != "" {
desc := i.Description
if i.DescWidth > 0 {
desc = fmt.Sprintf("%-*s", i.DescWidth, i.Description)
}
return style.Render(fmt.Sprintf("%s%s", prefix, paddedLabel)) +
RenderDescription(desc) + ColumnSeparator + statusBadge
}
return style.Render(fmt.Sprintf("%components.Item.renderExpandable method · go · L143-L158 (16 LOC)src/internal/presentation/components/tui_item.go
func (i Item) renderExpandable(selected bool, labelWidth int) string {
prefix := i.buildPrefix(selected)
paddedLabel := i.Label
if labelWidth > 0 {
paddedLabel = fmt.Sprintf("%-*s", labelWidth, i.Label)
}
style := theme.Normal
if selected {
style = theme.Selected
}
base := style.Render(fmt.Sprintf("%s%s", prefix, paddedLabel))
return base + RenderDescription(i.Description)
}components.Item.indentPrefix method · go · L160-L165 (6 LOC)src/internal/presentation/components/tui_item.go
func (i Item) indentPrefix() string {
if i.Indent <= 0 {
return ""
}
return strings.Repeat(" ", i.Indent*IndentSpaces)
}components.Item.buildPrefix method · go · L168-L174 (7 LOC)src/internal/presentation/components/tui_item.go
func (i Item) buildPrefix(selected bool) string {
indent := i.indentPrefix()
if selected {
return indent + " " + theme.IconSelected + " "
}
return indent + " "
}Powered by Repobility — scan your code at https://repobility.com
components.NewList function · go · L25-L35 (11 LOC)src/internal/presentation/components/tui_list.go
func NewList(items []Item) *List {
l := &List{
Items: items,
Cursor: 0,
Width: DefaultTerminalWidth,
Height: DefaultTerminalHeight,
}
// Start cursor on first selectable item
l.skipToSelectable(1)
return l
}components.List.move method · go · L54-L65 (12 LOC)src/internal/presentation/components/tui_list.go
func (l *List) move(delta int) {
newCursor := l.Cursor + delta
// Skip non-selectable items
for newCursor >= 0 && newCursor < len(l.Items) && !l.Items[newCursor].Selectable() {
newCursor += delta
}
if newCursor >= 0 && newCursor < len(l.Items) {
l.Cursor = newCursor
}
}components.List.Selected method · go · L75-L80 (6 LOC)src/internal/presentation/components/tui_list.go
func (l *List) Selected() *Item {
if l.Cursor >= 0 && l.Cursor < len(l.Items) {
return &l.Items[l.Cursor]
}
return nil
}components.List.Render method · go · L102-L130 (29 LOC)src/internal/presentation/components/tui_list.go
func (l *List) Render(visibleHeight int) string {
if len(l.Items) == 0 {
return ""
}
if visibleHeight <= 0 {
visibleHeight = l.Height
}
// Calculate visible range with scrolling
startIdx := 0
if l.Cursor > visibleHeight-ScrollMargin {
startIdx = l.Cursor - visibleHeight + ScrollMargin
}
endIdx := startIdx + visibleHeight
if endIdx > len(l.Items) {
endIdx = len(l.Items)
}
var b strings.Builder
for i := startIdx; i < endIdx; i++ {
item := l.Items[i]
selected := i == l.Cursor
line := item.Render(selected, l.LabelWidth, l.Width, l.SpinnerFrame)
b.WriteString(line + "\n")
}
return b.String()
}components.List.CalculateLabelWidth method · go · L133-L142 (10 LOC)src/internal/presentation/components/tui_list.go
func (l *List) CalculateLabelWidth() int {
maxLen := 0
for _, item := range l.Items {
if len(item.Label) > maxLen {
maxLen = len(item.Label)
}
}
l.LabelWidth = maxLen
return maxLen
}components.NewPage function · go · L22-L28 (7 LOC)src/internal/presentation/components/tui_page.go
func NewPage(title string) *Page {
return &Page{
Title: title,
Width: 80,
Height: 24,
}
}components.Page.ContentHeight method · go · L38-L44 (7 LOC)src/internal/presentation/components/tui_page.go
func (p *Page) ContentHeight() int {
h := p.Height - PageHeaderHeight(false) - 2 // header + help + message
if h < 1 {
h = 1
}
return h
}components.Page.Render method · go · L47-L78 (32 LOC)src/internal/presentation/components/tui_page.go
func (p *Page) Render() string {
var b strings.Builder
// Header
title := p.Title
if len(p.Breadcrumbs) > 0 {
title = p.Breadcrumbs[len(p.Breadcrumbs)-1]
}
b.WriteString(PageHeader(title, ""))
// Main content
if p.Content != "" {
b.WriteString(p.Content)
}
// Help text
if p.Help != "" {
b.WriteString(theme.Help.Render(p.Help))
}
// Status message
if p.Message != "" {
b.WriteString("\n")
if p.Processing {
b.WriteString(theme.Action.Render(p.Message))
} else {
b.WriteString(theme.Success.Render(p.Message))
}
}
return b.String()
}Same scanner, your repo: https://repobility.com — Repobility
components.Table function · go · L16-L41 (26 LOC)src/internal/presentation/components/tui_table.go
func Table(rows [][]string, columns []TableColumn) string {
if len(rows) == 0 {
return ""
}
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
if col < len(columns) {
if columns[col].Width > 0 {
style = style.Width(columns[col].Width)
}
if columns[col].Color != "" {
style = style.Foreground(lipgloss.Color(columns[col].Color))
}
}
return style
}).
Rows(rows...)
return t.Render()
}components.SimpleTable function · go · L45-L67 (23 LOC)src/internal/presentation/components/tui_table.go
func SimpleTable(rows [][]string, firstColWidth int) string {
if len(rows) == 0 {
return ""
}
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
StyleFunc(func(row, col int) lipgloss.Style {
if col == 0 {
return lipgloss.NewStyle().
Foreground(lipgloss.Color(theme.ColorPrimary)).
PaddingLeft(1).PaddingRight(1).
Width(firstColWidth)
}
return lipgloss.NewStyle().
Foreground(lipgloss.Color(theme.ColorMuted)).
PaddingLeft(1).PaddingRight(1)
}).
Rows(rows...)
return t.Render()
}components.StatusTable function · go · L71-L102 (32 LOC)src/internal/presentation/components/tui_table.go
func StatusTable(rows [][]string, nameWidth int) string {
if len(rows) == 0 {
return ""
}
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
StyleFunc(func(row, col int) lipgloss.Style {
switch col {
case 0:
return lipgloss.NewStyle().
Foreground(lipgloss.Color(theme.ColorPrimary)).
PaddingLeft(1).PaddingRight(1).
Width(nameWidth)
case 1:
return lipgloss.NewStyle().
Foreground(lipgloss.Color(theme.ColorMuted)).
PaddingLeft(1).PaddingRight(1).
Width(30)
case 2:
return lipgloss.NewStyle().
Foreground(lipgloss.Color(theme.ColorSecondary)).
PaddingLeft(1).PaddingRight(1)
default:
return lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
}
}).
Rows(rows...)
return t.Render()
}components.NewViewport function · go · L15-L20 (6 LOC)src/internal/presentation/components/tui_viewport.go
func NewViewport(width, height int) *Viewport {
return &Viewport{
Model: viewport.New(width, height),
ShowScrollIndicator: true,
}
}print.Row function · go · L113-L120 (8 LOC)src/internal/presentation/print/print.go
func Row(ok bool, label, detail string) {
icon := components.Badge(ok)
if detail != "" {
fmt.Printf(components.PageIndent+"%s %-14s %s\n", icon, label, theme.Muted.Render(detail))
} else {
fmt.Printf(components.PageIndent+"%s %s\n", icon, label)
}
}theme.Resolve function · go · L175-L192 (18 LOC)src/internal/presentation/theme/styles.go
func Resolve(styleName string) lipgloss.Style {
switch styleName {
case "success":
return Success
case "warning":
return Warning
case "danger":
return Danger
case "special":
return Special
case "normal":
return Normal
case "muted":
return Muted
default:
return Muted
}
}setup.InitRemoteState function · go · L41-L54 (14 LOC)src/internal/presentation/views/setup/remote.go
func InitRemoteState() {
settings, err := config.LoadRemoteSettings()
if err != nil {
settings = config.RemoteSettings{
Mode: config.RemoteModeUserspace,
AuthMethod: config.RemoteAuthOAuth,
}
}
remote = remoteState{
settings: settings,
itemData: nil,
}
}setup.BuildRemoteItems function · go · L57-L113 (57 LOC)src/internal/presentation/views/setup/remote.go
func BuildRemoteItems() []components.Item {
var items []components.Item
remote.itemData = nil
items = append(items, components.Item{Kind: components.KindHeader, Label: "Remote"})
remote.itemData = append(remote.itemData, remoteItemData{})
items = append(items, components.Item{
Kind: components.KindNavigation,
Label: "mode",
Description: string(remote.settings.Mode),
})
remote.itemData = append(remote.itemData, remoteItemData{action: remoteActionMode})
items = append(items, components.Item{
Kind: components.KindNavigation,
Label: "auth method",
Description: string(remote.settings.AuthMethod),
})
remote.itemData = append(remote.itemData, remoteItemData{action: remoteActionAuth})
hostDesc := remote.settings.Hostname
if hostDesc == "" {
hostDesc = "-"
}
items = append(items, components.Item{
Kind: components.KindNavigation,
Label: "hostname",
Description: hostDesc,
})
remote.itemData = append(remote.itemData, reRepobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
setup.HandleRemoteSelect function · go · L116-L163 (48 LOC)src/internal/presentation/views/setup/remote.go
func HandleRemoteSelect(index int, item components.Item) tea.Cmd {
if index >= len(remote.itemData) {
return nil
}
data := remote.itemData[index]
switch data.action {
case remoteActionMode:
remote.settings.Mode = nextRemoteMode(remote.settings.Mode)
return func() tea.Msg { return components.RefreshMsg{} }
case remoteActionAuth:
remote.settings.AuthMethod = nextRemoteAuthMethod(remote.settings.AuthMethod)
if remote.settings.AuthMethod == config.RemoteAuthOAuth {
remote.settings.Secret = ""
}
return func() tea.Msg { return components.RefreshMsg{} }
case remoteActionHostname:
return promptRemoteFieldCmd(
"hostname",
"Hostname (empty to clear): ",
false,
)
case remoteActionSecret:
if remote.settings.AuthMethod != config.RemoteAuthAuthKey {
return func() tea.Msg {
return components.ActionDoneMsg{Message: "Auth key is only used with auth method = authkey"}
}
}
return promptRemoteFieldCmd(
"secret",
"Auth key (empty to clear): ",setup.HandleRemoteMessage function · go · L166-L185 (20 LOC)src/internal/presentation/views/setup/remote.go
func HandleRemoteMessage(msg tea.Msg) tea.Cmd {
switch msg := msg.(type) {
case remoteFieldUpdatedMsg:
if msg.err != nil {
return func() tea.Msg {
return components.ActionDoneMsg{Message: "Error: " + msg.err.Error(), Err: msg.err}
}
}
value := strings.TrimSpace(msg.value)
switch msg.field {
case "hostname":
remote.settings.Hostname = value
case "secret":
remote.settings.Secret = value
}
return func() tea.Msg { return components.RefreshMsg{} }
}
return nil
}setup.RemoteConfig function · go · L188-L195 (8 LOC)src/internal/presentation/views/setup/remote.go
func RemoteConfig() components.AppConfig {
return components.AppConfig{
Title: "Remote",
BuildItems: BuildRemoteItems,
OnSelect: HandleRemoteSelect,
OnMessage: HandleRemoteMessage,
}
}setup.nextRemoteMode function · go · L197-L208 (12 LOC)src/internal/presentation/views/setup/remote.go
func nextRemoteMode(mode config.RemoteMode) config.RemoteMode {
order := []config.RemoteMode{
config.RemoteModeAuto,
config.RemoteModeUserspace,
}
for i := range order {
if order[i] == mode {
return order[(i+1)%len(order)]
}
}
return config.RemoteModeUserspace
}setup.nextRemoteAuthMethod function · go · L210-L221 (12 LOC)src/internal/presentation/views/setup/remote.go
func nextRemoteAuthMethod(method config.RemoteAuthMethod) config.RemoteAuthMethod {
order := []config.RemoteAuthMethod{
config.RemoteAuthOAuth,
config.RemoteAuthAuthKey,
}
for i := range order {
if order[i] == method {
return order[(i+1)%len(order)]
}
}
return config.RemoteAuthOAuth
}setup.promptRemoteFieldCmd function · go · L223-L252 (30 LOC)src/internal/presentation/views/setup/remote.go
func promptRemoteFieldCmd(field, prompt string, hidden bool) tea.Cmd {
tmpFile, err := os.CreateTemp("", "jremote-"+field+"-*")
if err != nil {
return func() tea.Msg {
return remoteFieldUpdatedMsg{field: field, err: err}
}
}
path := tmpFile.Name()
tmpFile.Close()
script := ""
if hidden {
script = "printf " + shellQuote(prompt) + "; stty -echo; IFS= read -r v; stty echo; printf '\\n'; printf '%s' \"$v\" > \"$1\""
} else {
script = "printf " + shellQuote(prompt) + "; IFS= read -r v; printf '%s' \"$v\" > \"$1\""
}
cmd := exec.Command("sh", "-c", script, "sh", path)
return tea.ExecProcess(cmd, func(execErr error) tea.Msg {
defer os.Remove(path)
if execErr != nil {
return remoteFieldUpdatedMsg{field: field, err: execErr}
}
data, readErr := os.ReadFile(path)
if readErr != nil {
return remoteFieldUpdatedMsg{field: field, err: readErr}
}
return remoteFieldUpdatedMsg{field: field, value: string(data)}
})
}setup.BuildItems function · go · L25-L135 (111 LOC)src/internal/presentation/views/setup/setup.go
func BuildItems() []components.Item {
var items []components.Item
itemNames = []string{}
// Navigation section
items = append(items, components.Item{Kind: components.KindHeader, Label: "Navigation"})
itemNames = append(itemNames, "")
items = append(items, components.Item{Kind: components.KindNavigation, Label: "skills", Description: "Manage AI agent skills"})
itemNames = append(itemNames, string(ActionSkills))
items = append(items, components.Item{Kind: components.KindNavigation, Label: "remote", Description: "Configure remote SSH access"})
itemNames = append(itemNames, string(ActionRemote))
// Configuration section - from config.Scripts with CheckFn
items = append(items, components.Item{Kind: components.KindHeader, Label: "Setup"})
itemNames = append(itemNames, "")
type scriptEntry struct {
item components.Item
name string
}
var configuredItems, notConfiguredItems []scriptEntry
// Calculate max description width for alignment
maxDescWidth := 0
for _, scriptsetup.HandleSelect function · go · L138-L176 (39 LOC)src/internal/presentation/views/setup/setup.go
func HandleSelect(index int, item components.Item, runScript func(string)) tea.Cmd {
if index >= len(itemNames) {
return nil
}
name := itemNames[index]
switch Action(name) {
case ActionSkills:
return func() tea.Msg {
return components.NavigateMsg{
InitFunc: InitSkillsState,
Config: SkillsConfig(),
}
}
case ActionRemote:
return func() tea.Msg {
return components.NavigateMsg{
InitFunc: InitRemoteState,
Config: RemoteConfig(),
}
}
default:
// Check if script uses ExecArgs (needs full terminal control)
if script := config.GetScriptByName(name); script != nil && len(script.ExecArgs) > 0 {
c := exec.Command(script.ExecArgs[0], script.ExecArgs[1:]...)
return tea.ExecProcess(c, func(err error) tea.Msg {
return components.ActionDoneMsg{Message: "Completed " + name}
})
}
loadingScript = name
return func() tea.Msg {
runScript(name)
loadingScript = ""
return components.ActionDoneMsg{Message: "Completed " + name}
All rows scored by the Repobility analyzer (https://repobility.com)
setup.RunOrExit function · go · L179-L187 (9 LOC)src/internal/presentation/views/setup/setup.go
func RunOrExit(runScript func(string)) {
components.RunOrExit(components.AppConfig{
Title: "Setup",
BuildItems: BuildItems,
OnSelect: func(index int, item components.Item) tea.Cmd {
return HandleSelect(index, item, runScript)
},
})
}setup.InitSkillsState function · go · L37-L44 (8 LOC)src/internal/presentation/views/setup/skills.go
func InitSkillsState() {
skills = skillsState{
expanded: make(map[string]bool),
installed: skill.ListInstalled(),
repoSkills: make(map[string][]string),
itemData: nil,
}
}setup.BuildSkillsItems function · go · L47-L160 (114 LOC)src/internal/presentation/views/setup/skills.go
func BuildSkillsItems() []components.Item {
var items []components.Item
skills.itemData = nil
// Favorites section
favorites := config.GetFavoriteSkills()
if len(favorites) > 0 {
items = append(items, components.Item{Kind: components.KindHeader, Label: "Pinned"})
skills.itemData = append(skills.itemData, skillItemData{})
for _, s := range favorites {
state := components.StateUnchecked
if skills.loadingSkill == s.Skill {
state = components.StateLoading
} else if isSkillInstalled(s.Skill) {
state = components.StateChecked
}
items = append(items, components.Item{
Kind: components.KindToggle,
Label: s.Skill,
State: state,
})
skills.itemData = append(skills.itemData, skillItemData{repo: s.Repo, skill: s.Skill})
}
}
// Installed section (skills not in Favorites)
var otherInstalled []string
for _, s := range skills.installed {
if !config.IsFavoriteSkill("", s) {
otherInstalled = append(otherInstalled, s)
}
}
if len(otherInsetup.isSkillInstalled function · go · L162-L169 (8 LOC)src/internal/presentation/views/setup/skills.go
func isSkillInstalled(name string) bool {
for _, s := range skills.installed {
if s == name {
return true
}
}
return false
}setup.findRepoForSkill function · go · L171-L185 (15 LOC)src/internal/presentation/views/setup/skills.go
func findRepoForSkill(name string) string {
for repoName, repoSkills := range skills.repoSkills {
for _, s := range repoSkills {
if s == name {
return repoName
}
}
}
for _, s := range config.FavoriteSkills {
if s.Skill == name {
return s.Repo
}
}
return ""
}setup.HandleSkillsSelect function · go · L188-L222 (35 LOC)src/internal/presentation/views/setup/skills.go
func HandleSkillsSelect(index int, item components.Item) tea.Cmd {
if index >= len(skills.itemData) {
return nil
}
data := skills.itemData[index]
switch item.Kind {
case components.KindExpandable:
if skills.expanded[data.repo] {
skills.expanded[data.repo] = false
return func() tea.Msg { return components.RefreshMsg{} }
} else {
skills.expanded[data.repo] = true
if skills.repoSkills[data.repo] == nil {
skills.loadingRepo = data.repo
return fetchSkillsCmd(data.repo)
}
return func() tea.Msg { return components.RefreshMsg{} }
}
case components.KindAction:
if data.action == skillActionInstallRepo {
return installRepoCmd(data.repo)
}
case components.KindToggle:
skills.loadingSkill = data.skill
if item.State == components.StateChecked {
return removeSkillCmd(data.skill)
}
return installSkillCmd(data.repo, data.skill)
}
return nil
}setup.HandleSkillsMessage function · go · L232-L249 (18 LOC)src/internal/presentation/views/setup/skills.go
func HandleSkillsMessage(msg tea.Msg) tea.Cmd {
switch msg := msg.(type) {
case SkillsFetchedMsg:
skills.loadingRepo = ""
if msg.Err == nil {
skills.repoSkills[msg.Repo] = msg.Skills
} else {
skills.repoSkills[msg.Repo] = []string{}
}
return nil
case components.ActionDoneMsg:
skills.loadingSkill = ""
skills.installed = skill.ListInstalled()
return nil
}
return nil
}setup.fetchSkillsCmd function · go · L251-L256 (6 LOC)src/internal/presentation/views/setup/skills.go
func fetchSkillsCmd(repo string) tea.Cmd {
return func() tea.Msg {
repoSkills, err := skill.ListFromRepo(repo)
return SkillsFetchedMsg{Repo: repo, Skills: repoSkills, Err: err}
}
}Powered by Repobility — scan your code at https://repobility.com
setup.installSkillCmd function · go · L258-L265 (8 LOC)src/internal/presentation/views/setup/skills.go
func installSkillCmd(repo, name string) tea.Cmd {
return func() tea.Msg {
if err := skill.Install(repo, name); err != nil {
return components.ActionDoneMsg{Message: "Error: " + err.Error(), Err: err}
}
return components.ActionDoneMsg{Message: "Installed " + name}
}
}setup.installRepoCmd function · go · L267-L274 (8 LOC)src/internal/presentation/views/setup/skills.go
func installRepoCmd(repo string) tea.Cmd {
return func() tea.Msg {
if err := skill.InstallAll(repo); err != nil {
return components.ActionDoneMsg{Message: "Error: " + err.Error(), Err: err}
}
return components.ActionDoneMsg{Message: "Installed all from " + repo}
}
}setup.removeSkillCmd function · go · L276-L283 (8 LOC)src/internal/presentation/views/setup/skills.go
func removeSkillCmd(name string) tea.Cmd {
return func() tea.Msg {
if err := skill.Remove(name); err != nil {
return components.ActionDoneMsg{Message: "Error: " + err.Error(), Err: err}
}
return components.ActionDoneMsg{Message: "Removed " + name}
}
}setup.SkillsConfig function · go · L286-L293 (8 LOC)src/internal/presentation/views/setup/skills.go
func SkillsConfig() components.AppConfig {
return components.AppConfig{
Title: "Skills",
BuildItems: BuildSkillsItems,
OnSelect: HandleSkillsSelect,
OnMessage: HandleSkillsMessage,
}
}status.New function · go · L42-L62 (21 LOC)src/internal/presentation/views/status/model.go
func New() Model {
loader := status.NewLoader()
items := make(map[string]status.Item)
itemOrder := loader.GetItems()
total := 0
for _, item := range itemOrder {
items[item.ID] = item
if !item.Loaded && item.Kind != status.KindHeader {
total++
}
}
return Model{
loader: loader,
items: items,
itemOrder: itemOrder,
spinner: components.NewSpinnerModel(),
total: total,
}
}status.Model.Init method · go · L65-L72 (8 LOC)src/internal/presentation/views/status/model.go
func (m Model) Init() tea.Cmd {
m.loader.Start()
return tea.Batch(
m.spinner.Tick,
m.loader.WaitForUpdate(),
scheduleProcessRefresh(),
)
}status.refreshProcesses function · go · L82-L90 (9 LOC)src/internal/presentation/views/status/model.go
func refreshProcesses() tea.Cmd {
return func() tea.Msg {
data := make(map[string][]config.ProcessInfo)
for _, check := range config.ProcessChecks {
data["process-"+check.Name] = check.CheckFn()
}
return ProcessDataMsg{Data: data}
}
}status.Model.Update method · go · L93-L183 (91 LOC)src/internal/presentation/views/status/model.go
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c", "esc":
m.quitting = true
return m, tea.Quit
case "home", "g":
m.viewport.GotoTop()
case "end", "G":
m.viewport.GotoBottom()
}
case tea.WindowSizeMsg:
headerHeight := components.PageHeaderHeight(true) // title + subtitle
footerHeight := 1
if !m.ready {
m.viewport = viewport.New(msg.Width, msg.Height-headerHeight-footerHeight)
m.viewport.YPosition = headerHeight
m.ready = true
} else {
m.viewport.Width = msg.Width
m.viewport.Height = msg.Height - headerHeight - footerHeight
}
m.width = msg.Width
m.height = msg.Height
case status.UpdateMsg:
if existing, ok := m.items[msg.ID]; ok {
existing.Loaded = msg.Item.Loaded
existing.Installed = msg.Item.Installed
existing.Version = msg.Item.Version
existing.Status = msg.Item.Status
existing.Detail = msg.Item.DetaSame scanner, your repo: https://repobility.com — Repobility
status.Model.View method · go · L186-L226 (41 LOC)src/internal/presentation/views/status/model.go
func (m Model) View() string {
if m.quitting {
return ""
}
if !m.ready {
return m.spinner.View() + " Initializing..."
}
var b strings.Builder
// System info subtitle
subtitle := ""
if sysinfo, ok := m.items["sysinfo"]; ok && sysinfo.Loaded {
subtitle = sysinfo.Detail
} else {
subtitle = m.spinner.View() + " Loading..."
}
// Header
b.WriteString(components.PageHeader("STATUS", subtitle))
// Content
b.WriteString(m.viewport.View())
b.WriteString("\n")
// Footer
scrollPercent := int(m.viewport.ScrollPercent() * 100)
help := fmt.Sprintf("↑/↓ scroll • g/G top/bottom • %d%% • q quit", scrollPercent)
if m.allLoaded {
footer := theme.Help.Render(help) + components.ColumnSeparator + theme.Success.Render(theme.IconCheck+" All checks complete")
b.WriteString(footer)
} else {
progressBar := m.renderProgressBar()
footer := theme.Help.Render(help) + components.ColumnSeparator + progressBar
b.WriteString(footer)
}
return b.String()
}status.Model.renderProgressBar method · go · L228-L248 (21 LOC)src/internal/presentation/views/status/model.go
func (m Model) renderProgressBar() string {
if m.allLoaded {
return theme.Success.Render(theme.IconCheck + " All checks complete")
}
width := 30
filled := int(float64(m.loaded) / float64(m.total) * float64(width))
if filled > width {
filled = width
}
bar := theme.ProgressFilled.Render(strings.Repeat(theme.IconProgressFull, filled)) +
theme.ProgressEmpty.Render(strings.Repeat(theme.IconProgressEmpty, width-filled))
return fmt.Sprintf("%s %s %d/%d",
m.spinner.View(),
bar,
m.loaded,
m.total,
)
}status.Model.renderTableRow method · go · L9-L37 (29 LOC)src/internal/presentation/views/status/rows.go
func (m Model) renderTableRow(item status.Item, colWidths ColumnWidths) string {
if !item.Loaded {
switch item.Kind {
case status.KindSetup:
return m.renderSetupRowLoading(item, colWidths)
case status.KindSecurity, status.KindIdentity:
return m.renderCheckRowLoading(item, colWidths)
case status.KindTool:
return m.renderToolRowLoading(item, colWidths)
case status.KindNetwork, status.KindCache:
return m.renderResourceRowLoading(item, colWidths)
default:
return components.RowPrefix + m.spinner.View() + components.ColumnSeparator + components.CellNormal(item.Name, colWidths.Name)
}
}
switch item.Kind {
case status.KindSetup:
return m.renderSetupRow(item, colWidths)
case status.KindSecurity, status.KindIdentity:
return m.renderCheckRow(item, colWidths)
case status.KindTool:
return m.renderToolRow(item, colWidths)
case status.KindNetwork, status.KindCache:
return m.renderResourceRow(item, colWidths)
}
return ""
}