diff --git a/docs/plugins.md b/docs/plugins.md index c10e3c9..81fe7f2 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -154,6 +154,9 @@ plugins: The config block is edited from the **Plugins** page in the TUI. Inside a plugin, call `get_config()` to retrieve the config as a Lua table. +Global defaults for any plugin can be set in `~/.config/spilltea/config.yaml` under a `plugins` key with the same structure as `plugins.yaml`. +These defaults are applied the first time a plugin is loaded in a project; once the plugin has an entry in the project's `plugins.yaml`, the project config takes full precedence and the global defaults are ignored. + `on_config()` is called once at startup (before `on_start`) and again every time the user saves the config in the TUI. It is the right place to read `get_config()` and populate local variables. diff --git a/internal/config/config.go b/internal/config/config.go index 8421a6c..1c74d8f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -54,6 +54,13 @@ type Config struct { } `mapstructure:"history"` Keybindings Keybindings `mapstructure:"keybindings"` + + Plugins map[string]GlobalPlugin `mapstructure:"plugins"` +} + +type GlobalPlugin struct { + Enable *bool `mapstructure:"enable"` + Config interface{} `mapstructure:"config"` } var Global *Config diff --git a/internal/plugins/manager.go b/internal/plugins/manager.go index 1c92ab0..c8c6e96 100644 --- a/internal/plugins/manager.go +++ b/internal/plugins/manager.go @@ -13,15 +13,23 @@ import ( "github.com/anotherhadi/spilltea/internal/intercept" goproxy "github.com/lqqyt2423/go-mitmproxy/proxy" lua "github.com/yuin/gopher-lua" + "gopkg.in/yaml.v3" ) +// GlobalDefault holds global defaults for a single plugin, read from config.yaml. +type GlobalDefault struct { + Enable *bool + Config interface{} +} + type Manager struct { mu sync.RWMutex plugins []*Plugin - db *db.DB - pluginsFile *PluginsFile - broker *intercept.Broker + db *db.DB + pluginsFile *PluginsFile + broker *intercept.Broker + globalDefaults map[string]GlobalDefault Notifs chan PluginNotifMsg Quit chan string @@ -48,6 +56,10 @@ func (m *Manager) SetPluginsFile(pf *PluginsFile) { m.pluginsFile = pf } +func (m *Manager) SetGlobalDefaults(defaults map[string]GlobalDefault) { + m.globalDefaults = defaults +} + func (m *Manager) LoadFromDir(dir string) error { entries, err := os.ReadDir(dir) if os.IsNotExist(err) { @@ -72,7 +84,17 @@ func (m *Manager) LoadFromDir(dir string) error { p.Enabled = enabled p.ConfigText = configText } else { - m.pluginsFile.register(p.ID, p.Enabled) + if def, ok := m.globalDefaults[p.ID]; ok { + if def.Enable != nil { + p.Enabled = *def.Enable + } + if def.Config != nil { + if raw, err := yaml.Marshal(def.Config); err == nil { + p.ConfigText = string(raw) + } + } + } + m.pluginsFile.register(p.ID, p.Enabled, p.ConfigText) } } m.mu.Lock() diff --git a/internal/plugins/pluginsfile.go b/internal/plugins/pluginsfile.go index 23dccaa..40d2e3a 100644 --- a/internal/plugins/pluginsfile.go +++ b/internal/plugins/pluginsfile.go @@ -66,9 +66,16 @@ func (pf *PluginsFile) get(id string) (enabled bool, config string, found bool) return e.Enable, string(raw), true } -func (pf *PluginsFile) register(id string, defaultEnabled bool) { +func (pf *PluginsFile) register(id string, defaultEnabled bool, configText string) { if _, ok := pf.data.Plugins[id]; !ok { - pf.data.Plugins[id] = pluginFileEntry{Enable: defaultEnabled} + entry := pluginFileEntry{Enable: defaultEnabled} + if configText != "" { + var parsed interface{} + if err := yaml.Unmarshal([]byte(configText), &parsed); err == nil { + entry.Config = parsed + } + } + pf.data.Plugins[id] = entry _ = pf.save() } } diff --git a/internal/ui/app/model.go b/internal/ui/app/model.go index c6a85f3..b1fde56 100644 --- a/internal/ui/app/model.go +++ b/internal/ui/app/model.go @@ -112,6 +112,14 @@ func New(broker *intercept.Broker, name, path string) Model { } mgr.SetPluginsFile(pf) + if len(cfg.Plugins) > 0 { + defaults := make(map[string]plugins.GlobalDefault, len(cfg.Plugins)) + for id, gp := range cfg.Plugins { + defaults[id] = plugins.GlobalDefault{Enable: gp.Enable, Config: gp.Config} + } + mgr.SetGlobalDefaults(defaults) + } + pluginsDir := config.ExpandPath(cfg.App.PluginsDir) if err := mgr.LoadFromDir(pluginsDir); err != nil { log.Printf("plugins: %v", err)