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