manager.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package theme
  2. import (
  3. "fmt"
  4. "slices"
  5. "strings"
  6. "sync"
  7. "github.com/alecthomas/chroma/v2/styles"
  8. )
  9. // Manager handles theme registration, selection, and retrieval.
  10. // It maintains a registry of available themes and tracks the currently active theme.
  11. type Manager struct {
  12. themes map[string]Theme
  13. currentName string
  14. mu sync.RWMutex
  15. }
  16. // Global instance of the theme manager
  17. var globalManager = &Manager{
  18. themes: make(map[string]Theme),
  19. currentName: "",
  20. }
  21. // RegisterTheme adds a new theme to the registry.
  22. // If this is the first theme registered, it becomes the default.
  23. func RegisterTheme(name string, theme Theme) {
  24. globalManager.mu.Lock()
  25. defer globalManager.mu.Unlock()
  26. globalManager.themes[name] = theme
  27. // If this is the first theme, make it the default
  28. if globalManager.currentName == "" {
  29. globalManager.currentName = name
  30. }
  31. }
  32. // SetTheme changes the active theme to the one with the specified name.
  33. // Returns an error if the theme doesn't exist.
  34. func SetTheme(name string) error {
  35. globalManager.mu.Lock()
  36. defer globalManager.mu.Unlock()
  37. delete(styles.Registry, "charm")
  38. if _, exists := globalManager.themes[name]; !exists {
  39. return fmt.Errorf("theme '%s' not found", name)
  40. }
  41. globalManager.currentName = name
  42. return nil
  43. }
  44. // CurrentTheme returns the currently active theme.
  45. // If no theme is set, it returns nil.
  46. func CurrentTheme() Theme {
  47. globalManager.mu.RLock()
  48. defer globalManager.mu.RUnlock()
  49. if globalManager.currentName == "" {
  50. return nil
  51. }
  52. return globalManager.themes[globalManager.currentName]
  53. }
  54. // CurrentThemeName returns the name of the currently active theme.
  55. func CurrentThemeName() string {
  56. globalManager.mu.RLock()
  57. defer globalManager.mu.RUnlock()
  58. return globalManager.currentName
  59. }
  60. // AvailableThemes returns a list of all registered theme names.
  61. func AvailableThemes() []string {
  62. globalManager.mu.RLock()
  63. defer globalManager.mu.RUnlock()
  64. names := make([]string, 0, len(globalManager.themes))
  65. for name := range globalManager.themes {
  66. names = append(names, name)
  67. }
  68. slices.SortFunc(names, func(a, b string) int {
  69. // list system theme first
  70. if a == "opencode" {
  71. return -1
  72. } else if b == "opencode" {
  73. return 1
  74. }
  75. return strings.Compare(a, b)
  76. })
  77. return names
  78. }
  79. // GetTheme returns a specific theme by name.
  80. // Returns nil if the theme doesn't exist.
  81. func GetTheme(name string) Theme {
  82. globalManager.mu.RLock()
  83. defer globalManager.mu.RUnlock()
  84. return globalManager.themes[name]
  85. }