on main help sign in
chore: add info to the splash screen
commitc74815335dee51eb7cde09c4f37d9baf339f16f4 authorKujtim Hoxha <kujtimii.h@gmail.com> dateThu 10 Jul 2025, 11:57 (1 year ago) parent647ec87
1 file changed+122−12
internal/tui/components/chat/splash/splash.go+122−12
internal/tui/components/chat/splash/splash.go+122−12
@@ -2,8 +2,9 @@ package splash
22
33import (
44 "fmt"
5− "log/slog"
5+ "os"
66 "slices"
7+ "strings"
78
89 "github.com/charmbracelet/bubbles/v2/key"
910 tea "github.com/charmbracelet/bubbletea/v2"
@@ -142,7 +143,6 @@ func (s *splashCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
142143 case tea.KeyPressMsg:
143144 switch {
144145 case key.Matches(msg, s.keyMap.Back):
145− slog.Info("Back key pressed in splash screen")
146146 if s.needsAPIKey {
147147 // Go back to model selection
148148 s.needsAPIKey = false
@@ -339,10 +339,10 @@ func (s *splashCmp) isProviderConfigured(providerID string) bool {
339339
340340func (s *splashCmp) View() string {
341341 t := styles.CurrentTheme()
342−
343342 var content string
344343 if s.needsAPIKey {
345− remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2)
344+ infoSection := s.infoSection()
345+ remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - lipgloss.Height(infoSection)
346346 apiKeyView := s.apiKeyInput.View()
347347 apiKeySelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render(
348348 lipgloss.JoinVertical(
@@ -353,10 +353,12 @@ func (s *splashCmp) View() string {
353353 content = lipgloss.JoinVertical(
354354 lipgloss.Left,
355355 s.logoRendered,
356+ infoSection,
356357 apiKeySelector,
357358 )
358359 } else if s.isOnboarding {
359− remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2)
360+ infoSection := s.infoSection()
361+ remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - lipgloss.Height(infoSection)
360362 modelListView := s.modelList.View()
361363 modelSelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render(
362364 lipgloss.JoinVertical(
@@ -369,11 +371,10 @@ func (s *splashCmp) View() string {
369371 content = lipgloss.JoinVertical(
370372 lipgloss.Left,
371373 s.logoRendered,
374+ infoSection,
372375 modelSelector,
373376 )
374377 } else if s.needsProjectInit {
375− t := styles.CurrentTheme()
376−
377378 titleStyle := t.S().Base.Foreground(t.FgBase)
378379 bodyStyle := t.S().Base.Foreground(t.FgMuted)
379380 shortcutStyle := t.S().Base.Foreground(t.Success)
@@ -403,8 +404,9 @@ func (s *splashCmp) View() string {
403404 })
404405
405406 buttons := lipgloss.JoinHorizontal(lipgloss.Left, yesButton, " ", noButton)
407+ infoSection := s.infoSection()
406408
407− remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2)
409+ remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - lipgloss.Height(infoSection)
408410
409411 initContent := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render(
410412 lipgloss.JoinVertical(
@@ -418,10 +420,15 @@ func (s *splashCmp) View() string {
418420 content = lipgloss.JoinVertical(
419421 lipgloss.Left,
420422 s.logoRendered,
423+ infoSection,
421424 initContent,
422425 )
423426 } else {
424− content = s.logoRendered
427+ parts := []string{
428+ s.logoRendered,
429+ s.infoSection(),
430+ }
431+ content = lipgloss.JoinVertical(lipgloss.Left, parts...)
425432 }
426433
427434 return t.S().Base.
@@ -451,6 +458,16 @@ func (s *splashCmp) Cursor() *tea.Cursor {
451458 return nil
452459}
453460
461+func (s *splashCmp) infoSection() string {
462+ return lipgloss.JoinVertical(
463+ lipgloss.Left,
464+ s.cwd(),
465+ "",
466+ lipgloss.JoinHorizontal(lipgloss.Left, s.lspBlock(), s.mcpBlock()),
467+ "",
468+ )
469+}
470+
454471func (s *splashCmp) logoBlock() string {
455472 t := styles.CurrentTheme()
456473 const padding = 2
@@ -471,8 +488,8 @@ func (m *splashCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor {
471488
472489 // Calculate the correct Y offset based on current state
473490 logoHeight := lipgloss.Height(m.logoRendered)
474− baseOffset := logoHeight + SplashScreenPaddingY
475−
491+ infoSectionHeight := lipgloss.Height(m.infoSection())
492+ baseOffset := logoHeight + SplashScreenPaddingY + infoSectionHeight
476493 if m.needsAPIKey {
477494 // For API key input, position at the bottom of the remaining space
478495 remainingHeight := m.height - logoHeight - (SplashScreenPaddingY * 2)
@@ -482,7 +499,7 @@ func (m *splashCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor {
482499 cursor.X = cursor.X + SplashScreenPaddingX
483500 } else if m.isOnboarding {
484501 // For model list, use the original calculation
485− listHeight := min(40, m.height-(SplashScreenPaddingY*2)-logoHeight-2)
502+ listHeight := min(40, m.height-(SplashScreenPaddingY*2)-logoHeight-1-infoSectionHeight)
486503 offset := m.height - listHeight
487504 cursor.Y += offset
488505 // Model list doesn't have a prompt, so add padding + space for list styling
@@ -516,3 +533,96 @@ func (s *splashCmp) Bindings() []key.Binding {
516533 }
517534 return []key.Binding{}
518535}
536+
537+func (s *splashCmp) getMaxInfoWidth() int {
538+ return min(s.width-(SplashScreenPaddingX*2), 40)
539+}
540+
541+func (s *splashCmp) cwd() string {
542+ cwd := config.Get().WorkingDir()
543+ t := styles.CurrentTheme()
544+ homeDir, err := os.UserHomeDir()
545+ if err == nil && cwd != homeDir {
546+ cwd = strings.ReplaceAll(cwd, homeDir, "~")
547+ }
548+ maxWidth := s.getMaxInfoWidth()
549+ return t.S().Muted.Width(maxWidth).Render(cwd)
550+}
551+
552+func LSPList(maxWidth int) []string {
553+ t := styles.CurrentTheme()
554+ lspList := []string{}
555+ lsp := config.Get().LSP.Sorted()
556+ if len(lsp) == 0 {
557+ return []string{t.S().Base.Foreground(t.Border).Render("None")}
558+ }
559+ for _, l := range lsp {
560+ iconColor := t.Success
561+ if l.LSP.Disabled {
562+ iconColor = t.FgMuted
563+ }
564+ lspList = append(lspList,
565+ core.Status(
566+ core.StatusOpts{
567+ IconColor: iconColor,
568+ Title: l.Name,
569+ Description: l.LSP.Command,
570+ },
571+ maxWidth,
572+ ),
573+ )
574+ }
575+ return lspList
576+}
577+
578+func (s *splashCmp) lspBlock() string {
579+ t := styles.CurrentTheme()
580+ maxWidth := s.getMaxInfoWidth() / 2
581+ section := t.S().Subtle.Render("LSPs")
582+ lspList := append([]string{section, ""}, LSPList(maxWidth-1)...)
583+ return t.S().Base.Width(maxWidth).PaddingRight(1).Render(
584+ lipgloss.JoinVertical(
585+ lipgloss.Left,
586+ lspList...,
587+ ),
588+ )
589+}
590+
591+func MCPList(maxWidth int) []string {
592+ t := styles.CurrentTheme()
593+ mcpList := []string{}
594+ mcps := config.Get().MCP.Sorted()
595+ if len(mcps) == 0 {
596+ return []string{t.S().Base.Foreground(t.Border).Render("None")}
597+ }
598+ for _, l := range mcps {
599+ iconColor := t.Success
600+ if l.MCP.Disabled {
601+ iconColor = t.FgMuted
602+ }
603+ mcpList = append(mcpList,
604+ core.Status(
605+ core.StatusOpts{
606+ IconColor: iconColor,
607+ Title: l.Name,
608+ Description: l.MCP.Command,
609+ },
610+ maxWidth,
611+ ),
612+ )
613+ }
614+ return mcpList
615+}
616+
617+func (s *splashCmp) mcpBlock() string {
618+ t := styles.CurrentTheme()
619+ maxWidth := s.getMaxInfoWidth() / 2
620+ section := t.S().Subtle.Render("MCPs")
621+ mcpList := append([]string{section, ""}, MCPList(maxWidth-1)...)
622+ return t.S().Base.Width(maxWidth).PaddingRight(1).Render(
623+ lipgloss.JoinVertical(
624+ lipgloss.Left,
625+ mcpList...,
626+ ),
627+ )
628+}