diff --git a/Makefile b/Makefile index 7f25730..11e9166 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ goimports: proto: autogenpb --proto widget.proto + autogenpb --proto toolkitConfig.proto clean: rm -f go.* *.pb.go diff --git a/config.go b/config.go new file mode 100644 index 0000000..a68b562 --- /dev/null +++ b/config.go @@ -0,0 +1,116 @@ +// Copyright 2025 WIT.COM Inc Licensed GPL 3.0 + +package tree + +// functions to import and export the protobuf +// data to and from config files + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "go.wit.com/log" +) + +// load the ~/.config/forge/ files +func configLoad() *ToolkitConfigs { + if os.Getenv("FORGE_CONFIG") == "" { + homeDir, _ := os.UserHomeDir() + fullpath := filepath.Join(homeDir, ".config/forge") + os.Setenv("FORGE_CONFIG", fullpath) + } + + c, err := loadText() + if err != nil { + log.Info("gui toolkit configLoad() error", err) + } + if c != nil { + return c + } + + // first time user. make a template config file + c = sampleConfig() + return c +} + +// makes a sample config (and saves it) +func sampleConfig() *ToolkitConfigs { + all := NewToolkitConfigs() + new1 := new(ToolkitConfig) + new1.Plugin = "tree" + new1.Name = "test" + new1.Value = "apple" + all.Append(new1) + + all.configSave() + + fmt.Println("first time user. adding an example config file with", len(all.ToolkitConfigs), "repos") + return all +} + +// write to ~/.config/forge/ unless ENV{FORGE_CONFIG} is set +func (c *ToolkitConfigs) configSave() error { + s := c.FormatTEXT() + configWrite("toolkit.text", []byte(s)) + return nil +} + +func loadText() (*ToolkitConfigs, error) { + // this lets the user hand edit the config + data, err := loadFile("toolkit.text") + if err != nil { + return nil, err + } + if data == nil { + return nil, fmt.Errorf("toolkit.text data was nil") + } + if len(data) == 0 { + return nil, fmt.Errorf("toolkit.text was empty") + } + + c := new(ToolkitConfigs) + + // attempt to marshal toolkit.text + if err := c.UnmarshalTEXT(data); err != nil { + return nil, err + } + log.Log(TREE, "ConfigLoad()", len(c.ToolkitConfigs), "entries in ~/.config/forge") + return c, nil +} + +func loadFile(filename string) ([]byte, error) { + fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) + data, err := os.ReadFile(fullname) + if errors.Is(err, os.ErrNotExist) { + // if file does not exist, just return nil. this + // will cause ConfigLoad() to try the next config file like "toolkit.text" + // because the user might want to edit the .config by hand + return nil, nil + } + if err != nil { + // log.Info("open config file :", err) + return nil, err + } + return data, nil +} + +func configWrite(filename string, data []byte) error { + fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) + + cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + defer cfgfile.Close() + if err != nil { + log.Warn("open config file :", err) + return err + } + if filename == "toolkit.text" { + // add header + cfgfile.Write([]byte("\n")) + cfgfile.Write([]byte("# you can customize your GUI toolkit user settings here\n")) + cfgfile.Write([]byte("\n")) + } + cfgfile.Write(data) + return nil +} diff --git a/init.go b/init.go index f87bbb5..19a828b 100644 --- a/init.go +++ b/init.go @@ -5,6 +5,7 @@ package tree import ( + "fmt" "os" "runtime/debug" "sync" @@ -109,9 +110,25 @@ func (me *TreeInfo) catchActionChannel() { func New() *TreeInfo { me := new(TreeInfo) me.pluginChan = make(chan widget.Action, 1) + me.config = configLoad() log.Log(TREE, "Init() start channel reciever") go me.catchActionChannel() log.Log(TREE, "Init() END") return me } + +func (t *TreeInfo) ConfigFind(n string) (string, error) { + all := t.config.All() // get the list of repos + for all.Scan() { + r := all.Next() + if t.PluginName != r.Plugin { + continue + } + if n == r.Name { + return r.Value, nil + } + log.Info("toolkit config", r.Plugin, r.Name, r.Value, n) + } + return "", fmt.Errorf("toolkit config %s not found", n) +} diff --git a/structs.go b/structs.go index a3b9a63..eb76f39 100644 --- a/structs.go +++ b/structs.go @@ -18,6 +18,7 @@ var treeRoot *Node type TreeInfo struct { PluginName string + config *ToolkitConfigs // this is the channel we send user events like // mouse clicks or keyboard events back to the program diff --git a/toolkitConfig.proto b/toolkitConfig.proto new file mode 100644 index 0000000..a53fdc4 --- /dev/null +++ b/toolkitConfig.proto @@ -0,0 +1,19 @@ +// Copyright 2025 WIT.COM Inc Licensed GPL 3.0 + +syntax = "proto3"; + +package forgepb; + +import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp + +message ToolkitConfig { // + string plugin = 1; // 'gocui', 'andlabs', etc + string name = 2; // variable name 'fullscreen' + string value = 3; // value "true" +} + +message ToolkitConfigs { // `autogenpb:marshal` `autogenpb:nomutex` + string uuid = 1; // `autogenpb:uuid:d7886d47-a3b9-43b9-b0f6-17074a9844e6` + string version = 2; // `autogenpb:version:v0.0.1` + repeated ToolkitConfig ToolkitConfigs = 3; +}