| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- package app
- import (
- "context"
- "database/sql"
- "maps"
- "sync"
- "time"
- "github.com/opencode-ai/opencode/internal/config"
- "github.com/opencode-ai/opencode/internal/db"
- "github.com/opencode-ai/opencode/internal/history"
- "github.com/opencode-ai/opencode/internal/llm/agent"
- "github.com/opencode-ai/opencode/internal/logging"
- "github.com/opencode-ai/opencode/internal/lsp"
- "github.com/opencode-ai/opencode/internal/message"
- "github.com/opencode-ai/opencode/internal/permission"
- "github.com/opencode-ai/opencode/internal/session"
- "github.com/opencode-ai/opencode/internal/tui/theme"
- )
- type App struct {
- Sessions session.Service
- Messages message.Service
- History history.Service
- Permissions permission.Service
- CoderAgent agent.Service
- LSPClients map[string]*lsp.Client
- clientsMutex sync.RWMutex
- watcherCancelFuncs []context.CancelFunc
- cancelFuncsMutex sync.Mutex
- watcherWG sync.WaitGroup
- }
- func New(ctx context.Context, conn *sql.DB) (*App, error) {
- q := db.New(conn)
- sessions := session.NewService(q)
- messages := message.NewService(q)
- files := history.NewService(q, conn)
- app := &App{
- Sessions: sessions,
- Messages: messages,
- History: files,
- Permissions: permission.NewPermissionService(),
- LSPClients: make(map[string]*lsp.Client),
- }
- // Initialize theme based on configuration
- app.initTheme()
- // Initialize LSP clients in the background
- go app.initLSPClients(ctx)
- var err error
- app.CoderAgent, err = agent.NewAgent(
- config.AgentCoder,
- app.Sessions,
- app.Messages,
- agent.CoderAgentTools(
- app.Permissions,
- app.Sessions,
- app.Messages,
- app.History,
- app.LSPClients,
- ),
- )
- if err != nil {
- logging.Error("Failed to create coder agent", err)
- return nil, err
- }
- return app, nil
- }
- // initTheme sets the application theme based on the configuration
- func (app *App) initTheme() {
- cfg := config.Get()
- if cfg == nil || cfg.TUI.Theme == "" {
- return // Use default theme
- }
- // Try to set the theme from config
- err := theme.SetTheme(cfg.TUI.Theme)
- if err != nil {
- logging.Warn("Failed to set theme from config, using default theme", "theme", cfg.TUI.Theme, "error", err)
- } else {
- logging.Debug("Set theme from config", "theme", cfg.TUI.Theme)
- }
- }
- // Shutdown performs a clean shutdown of the application
- func (app *App) Shutdown() {
- // Cancel all watcher goroutines
- app.cancelFuncsMutex.Lock()
- for _, cancel := range app.watcherCancelFuncs {
- cancel()
- }
- app.cancelFuncsMutex.Unlock()
- app.watcherWG.Wait()
- // Perform additional cleanup for LSP clients
- app.clientsMutex.RLock()
- clients := make(map[string]*lsp.Client, len(app.LSPClients))
- maps.Copy(clients, app.LSPClients)
- app.clientsMutex.RUnlock()
- for name, client := range clients {
- shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- if err := client.Shutdown(shutdownCtx); err != nil {
- logging.Error("Failed to shutdown LSP client", "name", name, "error", err)
- }
- cancel()
- }
- }
|