session.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package dialog
  2. import (
  3. "context"
  4. tea "github.com/charmbracelet/bubbletea/v2"
  5. "github.com/sst/opencode/internal/app"
  6. "github.com/sst/opencode/internal/components/list"
  7. "github.com/sst/opencode/internal/components/modal"
  8. "github.com/sst/opencode/internal/layout"
  9. "github.com/sst/opencode/internal/styles"
  10. "github.com/sst/opencode/internal/theme"
  11. "github.com/sst/opencode/internal/util"
  12. "github.com/sst/opencode/pkg/client"
  13. )
  14. // SessionDialog interface for the session switching dialog
  15. type SessionDialog interface {
  16. layout.Modal
  17. }
  18. type sessionItem client.SessionInfo
  19. func (s sessionItem) Render(selected bool, width int) string {
  20. t := theme.CurrentTheme()
  21. baseStyle := styles.BaseStyle().
  22. Width(width - 4).
  23. Background(t.BackgroundElement())
  24. if selected {
  25. baseStyle = baseStyle.
  26. Background(t.Primary()).
  27. Foreground(t.BackgroundElement()).
  28. Bold(true)
  29. } else {
  30. baseStyle = baseStyle.
  31. Foreground(t.Text())
  32. }
  33. return baseStyle.Padding(0, 1).Render(s.Title)
  34. }
  35. type sessionDialog struct {
  36. width int
  37. height int
  38. modal *modal.Modal
  39. selectedSessionID string
  40. list list.List[sessionItem]
  41. }
  42. func (s *sessionDialog) Init() tea.Cmd {
  43. return nil
  44. }
  45. func (s *sessionDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  46. switch msg := msg.(type) {
  47. case tea.WindowSizeMsg:
  48. s.width = msg.Width
  49. s.height = msg.Height
  50. s.list.SetMaxWidth(layout.Current.Container.Width - 12)
  51. case tea.KeyPressMsg:
  52. switch msg.String() {
  53. case "enter":
  54. if item, idx := s.list.GetSelectedItem(); idx >= 0 {
  55. s.selectedSessionID = item.Id
  56. return s, tea.Sequence(
  57. util.CmdHandler(modal.CloseModalMsg{}),
  58. util.CmdHandler(app.SessionSelectedMsg(&item)),
  59. )
  60. }
  61. }
  62. }
  63. var cmd tea.Cmd
  64. listModel, cmd := s.list.Update(msg)
  65. s.list = listModel.(list.List[sessionItem])
  66. return s, cmd
  67. }
  68. func (s *sessionDialog) Render(background string) string {
  69. return s.modal.Render(s.list.View(), background)
  70. }
  71. func (s *sessionDialog) Close() tea.Cmd {
  72. return nil
  73. }
  74. // NewSessionDialog creates a new session switching dialog
  75. func NewSessionDialog(app *app.App) SessionDialog {
  76. sessions, _ := app.ListSessions(context.Background())
  77. var sessionItems []sessionItem
  78. for _, sess := range sessions {
  79. if sess.ParentID != nil {
  80. continue
  81. }
  82. sessionItems = append(sessionItems, sessionItem(sess))
  83. }
  84. list := list.NewListComponent(
  85. sessionItems,
  86. 10, // maxVisibleSessions
  87. "No sessions available",
  88. true, // useAlphaNumericKeys
  89. )
  90. return &sessionDialog{
  91. list: list,
  92. modal: modal.New(modal.WithTitle("Switch Session"), modal.WithMaxWidth(80)),
  93. }
  94. }