session.go 2.7 KB

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