From c43a684857b58b4d9b926db8d74837ed74e9ddd6 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Sun, 6 Nov 2022 19:57:20 -0600 Subject: [PATCH] Implement a early AddButton() via a golang plugin pass a name to gocui.AddButton() cleaner plugin usage add the start to golang plugin plugin stuff in a single file added a button correctly andlabs/ui added a button via plugin to gocli hot diggity! trying to invoke a gocli plugin function from the andlabs ui load the plugin hide more debugging output turn off all output Signed-off-by: Jeff Carr --- cmds/buttonAsPlugin/Makefile | 2 +- cmds/buttonAsPlugin/log.go | 64 +++++++++++++++++++++++++ cmds/buttonAsPlugin/main.go | 31 +++++++++++-- group.go | 5 +- main.go | 7 ++- plugin.go | 90 ++++++++++++++++++++++++++++++++++++ structs.go | 7 ++- toolkit/andlabs/box.go | 20 ++++++-- toolkit/andlabs/common.go | 8 +++- toolkit/andlabs/main.go | 8 +++- toolkit/andlabs/structs.go | 6 ++- toolkit/andlabs/window.go | 12 +++-- toolkit/gocui/greeter.go | 19 ++++++-- toolkit/gocui/main.go | 20 ++++---- toolkit/gocui/newJ.go | 2 +- 15 files changed, 260 insertions(+), 41 deletions(-) create mode 100644 cmds/buttonAsPlugin/log.go create mode 100644 plugin.go diff --git a/cmds/buttonAsPlugin/Makefile b/cmds/buttonAsPlugin/Makefile index 431d956..d9a67bf 100644 --- a/cmds/buttonAsPlugin/Makefile +++ b/cmds/buttonAsPlugin/Makefile @@ -1,5 +1,5 @@ run: build - ./buttonAsPlugin + ./buttonAsPlugin >/tmp/buttonAsPlugin.log 2>&1 build-release: go get -v -u -x . diff --git a/cmds/buttonAsPlugin/log.go b/cmds/buttonAsPlugin/log.go new file mode 100644 index 0000000..642ff7b --- /dev/null +++ b/cmds/buttonAsPlugin/log.go @@ -0,0 +1,64 @@ +// This creates a simple hello world window +package main + +import ( + "log" + "fmt" + "os" + "io" + "time" + "bufio" + arg "github.com/alexflint/go-arg" +) + + +var args struct { + Foo string + Bar bool + User string `arg:"env:USER"` + Demo bool `help:"run a demo"` +} + +var f1 *os.File +var f2 *os.File +var err error + +func init() { + arg.MustParse(&args) + fmt.Println(args.Foo, args.Bar, args.User) + + f1, err = os.OpenFile("/tmp/guilogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) + if err != nil { + log.Fatalf("error opening file: %v", err) + } + // hmm. is there a trick here or must this be in main() + // defer f.Close() + + log.SetOutput(f1) + log.Println("This is a test log entry") +} + +func captureSTDOUT() { + f2, _ = os.OpenFile("/tmp/my.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) + multiWriter := io.MultiWriter(os.Stderr, f2) + rd, wr, err := os.Pipe() + if err != nil { + os.Exit(1) + } + + // overwrite os.Stdout + os.Stderr = wr + + go func() { + scanner := bufio.NewScanner(rd) + for scanner.Scan() { + stdoutLine := scanner.Text() + multiWriter.Write([]byte(stdoutLine + "\n")) + } + }() + + fmt.Println("foobar") + + // hacky sleep to ensure the go routine can write before program exits + time.Sleep(time.Second) +} diff --git a/cmds/buttonAsPlugin/main.go b/cmds/buttonAsPlugin/main.go index 1c2eeaf..e26c75e 100644 --- a/cmds/buttonAsPlugin/main.go +++ b/cmds/buttonAsPlugin/main.go @@ -7,6 +7,12 @@ import ( ) func main() { + // go loadPlugin(plugHello, "../../toolkit/hello.so") + + // this doesn't seem to work + captureSTDOUT() + + // go loadPlugin("../../toolkit/gocli.so") gui.Main(buttonWindow) } @@ -17,9 +23,6 @@ func buttonWindow() { gui.Config.Width = 640 gui.Config.Height = 480 -// gui.Config.Exit = gui.StandardClose -// gui.SetDebug(true) - w = gui.NewWindow() g = w.NewGroup("buttonGroup") @@ -27,7 +30,25 @@ func buttonWindow() { log.Println("world") }) - g.NewButton("foo", func () { - log.Println("bar") + /* + g.NewButton("LoadPlugin()", func () { + log.Println("world") + gui.LoadPlugin("../../toolkit/gocli.so") + }) + */ + + g.NewButton("RunGreet()", func () { + log.Println("world") + go gui.RunGreet() + }) + + g.NewButton("gui.LookupJcarrButton()", func () { + log.Println("gui.LookupJcarrButton()") + gui.LookupJcarrButton() + }) + + g.NewButton("gui.GocuiAddButton()", func () { + log.Println("gui.GocuiAddButton()") + gui.GocuiAddButton("new foobar") }) } diff --git a/group.go b/group.go index 07ec1b9..7e60b23 100644 --- a/group.go +++ b/group.go @@ -9,7 +9,10 @@ import toolkit "git.wit.org/wit/gui/toolkit/andlabs" func (n *Node) NewGroup(name string) *Node { var newT *toolkit.Toolkit var gNode *Node - log.Println("toolkit.NewGroup() START", name) + + if (GetDebug()) { + log.Println("toolkit.NewGroup() START", name) + } if (n.toolkit == nil) { log.Println("toolkit.NewGroup() toolkit == nil") diff --git a/main.go b/main.go index 30eb6a7..e3e6609 100644 --- a/main.go +++ b/main.go @@ -29,10 +29,15 @@ func init() { if (Config.Options.Debug) { Config.master.Dump() } + + // load the gocli plugin + PlugGocli = LoadPlugin("../../toolkit/gocli.so") } func Main(f func()) { - log.Println("Starting gui.Main() (using gtk via andlabs/ui)") + if (Config.Options.Debug) { + log.Println("Starting gui.Main() (using gtk via andlabs/ui)") + } toolkit.Main(f) } diff --git a/plugin.go b/plugin.go new file mode 100644 index 0000000..5c10e03 --- /dev/null +++ b/plugin.go @@ -0,0 +1,90 @@ +package gui + +import ( + "log" + "os" + + "plugin" + "github.com/davecgh/go-spew/spew" +) + +type Greeter interface { + Greet() + JcarrButton() + AddButton(string) +} + +var PlugGocli *plugin.Plugin +var PlugHello *plugin.Plugin + +// var gBut plugin.Symbol +var jcarrBut plugin.Symbol +var symGreeter plugin.Symbol +var greeter Greeter +var ok bool + +func LoadPlugin(name string) *plugin.Plugin { + scs := spew.ConfigState{MaxDepth: 1} + + // load module + // 1. open the so file to load the symbols + plug, err := plugin.Open(name) + log.Println("plug =") + log.Println(scs.Sdump(plug)) + if err != nil { + log.Println(err) + os.Exit(1) + } + PlugGocli = plug + + // 2. look up a symbol (an exported function or variable) + // in this case, variable Greeter + symGreeter, err = plug.Lookup("Greeter") + log.Println("symGreater", symGreeter) + log.Println(scs.Sdump(symGreeter)) + if err != nil { + log.Println(err) + os.Exit(1) + } + + // 3. Assert that loaded symbol is of a desired type + // in this case interface type Greeter (defined above) + // var greeter Greeter + greeter, ok = symGreeter.(Greeter) + log.Println("greeter", symGreeter) + log.Println(scs.Sdump(greeter)) + if !ok { + log.Println("unexpected type from module symbol") + os.Exit(1) + } + return plug +} + +func RunGreet() { + log.Println("gui.RunGreet() START") + if (greeter == nil) { + log.Println("wit/gui gocui plugin didn't load") + return + } + greeter.Greet() +} + +func LookupJcarrButton() { + log.Println("lookupJcarrButton() START") + + if (greeter == nil) { + log.Println("wit/gui gocui plugin didn't load") + return + } + greeter.JcarrButton() +} + +func GocuiAddButton(name string) { + log.Println("GocuiAddButton() START", name) + + if (greeter == nil) { + log.Println("wit/gui gocui plugin didn't load") + return + } + greeter.AddButton(name) +} diff --git a/structs.go b/structs.go index 2a0493e..bf16758 100644 --- a/structs.go +++ b/structs.go @@ -46,13 +46,13 @@ func ShowDebugValues() { log.Println("\t wit/gui DebugDump =", Config.Options.DebugDump) log.Println("\t wit/gui DebugNode =", Config.Options.DebugNode) log.Println("\t wit/gui DebugTabs =", Config.Options.DebugTabs) -// log.Println("\t wit/gui DebugTable =", Config.Options.DebugTable) -// log.Println("\t wit/gui DebugWindow =", Config.Options.DebugWindow) + log.Println("\t wit/gui DebugPlugin =", Config.Options.DebugPlugin) log.Println("\t wit/gui DebugChange =", Config.Options.DebugChange) log.Println("\t wit/gui DebugToolkit =", toolkit.DebugToolkit) } +// This struct can be used with go-arg type GuiOptions struct { // These are global debugging settings // TODO: move to a standard logging system @@ -60,8 +60,7 @@ type GuiOptions struct { DebugDump bool DebugNode bool DebugTabs bool -// DebugTable bool -// DebugWindow bool + DebugPlugin bool DebugChange bool `help:"debug mouse clicks and keyboard input"` } diff --git a/toolkit/andlabs/box.go b/toolkit/andlabs/box.go index 8347bab..29a8331 100644 --- a/toolkit/andlabs/box.go +++ b/toolkit/andlabs/box.go @@ -12,10 +12,14 @@ func (t *Toolkit) GetBox() *ui.Box { // create a new box func (t *Toolkit) NewBox() *Toolkit { - log.Println("gui.Toolbox.NewBox() START create default") + if (DebugToolkit) { + log.Println("gui.Toolbox.NewBox() START create default") + } t.Dump() if (t.uiGroup != nil) { - log.Println("\tgui.Toolbox.NewBox() is a Group") + if (DebugToolkit) { + log.Println("\tgui.Toolbox.NewBox() is a Group") + } var newTK Toolkit vbox := ui.NewVerticalBox() @@ -26,7 +30,9 @@ func (t *Toolkit) NewBox() *Toolkit { return &newTK } if (t.uiBox != nil) { - log.Println("\tgui.Toolbox.NewBox() is a Box") + if (DebugToolkit) { + log.Println("\tgui.Toolbox.NewBox() is a Box") + } var newTK Toolkit vbox := ui.NewVerticalBox() @@ -38,7 +44,9 @@ func (t *Toolkit) NewBox() *Toolkit { return &newTK } if (t.uiWindow != nil) { - log.Println("\tgui.Toolbox.NewBox() is a Window") + if (DebugToolkit) { + log.Println("\tgui.Toolbox.NewBox() is a Window") + } var newT Toolkit vbox := ui.NewVerticalBox() @@ -50,7 +58,9 @@ func (t *Toolkit) NewBox() *Toolkit { // panic("WTF") return &newT } - log.Println("\tgui.Toolbox.NewBox() FAILED. Couldn't figure out where to make a box") + if (DebugToolkit) { + log.Println("\tgui.Toolbox.NewBox() FAILED. Couldn't figure out where to make a box") + } t.Dump() return nil } diff --git a/toolkit/andlabs/common.go b/toolkit/andlabs/common.go index e997aca..451f9d6 100644 --- a/toolkit/andlabs/common.go +++ b/toolkit/andlabs/common.go @@ -3,7 +3,9 @@ package toolkit import "log" func init() { - log.Println("gui/toolkit init() Setting defaultBehavior = true") + if (DebugToolkit) { + log.Println("gui/toolkit init() Setting defaultBehavior = true") + } setDefaultBehavior(true) } @@ -37,7 +39,9 @@ func (t Toolkit) commonChange(widget string) { func (t *Toolkit) broken() bool { if (t.uiBox == nil) { if (t.uiWindow != nil) { - log.Println("gui.Toolkit.UiBox == nil. This is an empty window. Try to add a box") + if (DebugToolkit) { + log.Println("gui.Toolkit.UiBox == nil. This is an empty window. Try to add a box") + } t.NewBox() return false } diff --git a/toolkit/andlabs/main.go b/toolkit/andlabs/main.go index d1dc7e6..da639fa 100644 --- a/toolkit/andlabs/main.go +++ b/toolkit/andlabs/main.go @@ -9,7 +9,9 @@ import ( ) func Main(f func()) { - log.Println("Starting gui.Main() (using gtk via andlabs/ui)") + if (DebugToolkit) { + log.Println("Starting gui.Main() (using gtk via andlabs/ui)") + } ui.Main(f) } @@ -22,6 +24,8 @@ func Main(f func()) { // For example: Queue(NewWindow()) // func Queue(f func()) { - log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)") + if (DebugToolkit) { + log.Println("Sending function to gui.Main() (using gtk via andlabs/ui)") + } ui.QueueMain(f) } diff --git a/toolkit/andlabs/structs.go b/toolkit/andlabs/structs.go index 374627c..9bba671 100644 --- a/toolkit/andlabs/structs.go +++ b/toolkit/andlabs/structs.go @@ -21,8 +21,10 @@ var DebugToolkit bool func setDefaultBehavior(s bool) { defaultBehavior = s if (defaultBehavior) { - log.Println("Setting this toolkit to use the default behavior.") - log.Println("This is the 'guessing' part as defined by the wit/gui 'Principles'. Refer to the docs.") + if (DebugToolkit) { + log.Println("Setting this toolkit to use the default behavior.") + log.Println("This is the 'guessing' part as defined by the wit/gui 'Principles'. Refer to the docs.") + } stretchy = false padded = true menubar = true diff --git a/toolkit/andlabs/window.go b/toolkit/andlabs/window.go index 3e5f16a..efbd672 100644 --- a/toolkit/andlabs/window.go +++ b/toolkit/andlabs/window.go @@ -17,7 +17,9 @@ func (t *Toolkit) ErrorWindow(msg1 string, msg2 string) { func NewWindow(title string, x int, y int) *Toolkit { var t Toolkit - log.Println("toolkit NewWindow", title, x, y) + if (DebugToolkit) { + log.Println("toolkit NewWindow", title, x, y) + } w := ui.NewWindow(title, x, y, menubar) w.SetBorderless(canvas) w.SetMargined(margin) @@ -50,11 +52,15 @@ func NewWindow(title string, x int, y int) *Toolkit { } func (t *Toolkit) SetWindowTitle(title string) { - log.Println("toolkit NewWindow", t.Name, "title", title) + if (DebugToolkit) { + log.Println("toolkit NewWindow", t.Name, "title", title) + } win := t.uiWindow if (win != nil) { win.SetTitle(title) } else { - log.Println("Setting the window title", title) + if (DebugToolkit) { + log.Println("Setting the window title", title) + } } } diff --git a/toolkit/gocui/greeter.go b/toolkit/gocui/greeter.go index 9d546a7..de6ee68 100644 --- a/toolkit/gocui/greeter.go +++ b/toolkit/gocui/greeter.go @@ -11,6 +11,8 @@ import ( type greeting string +// this is exported +var Greeter greeting // func main() { func (g greeting) Greet() { @@ -19,16 +21,25 @@ func (g greeting) Greet() { // ToolkitMain() } -// this is exported -var Greeter greeting +func (g greeting) JcarrButton() { + fmt.Println("Hello GreetButton meet Universe") + addButton("Greet foo") + addButton("Greet foo 2") +} -func AddGroup(name string) { +func addGroup(name string) { log.Println("addGroup()", name) currentY = 2 currentX += groupSize + 6 } -func AddButton(name string) error { +func (g greeting) AddButton(name string) { +// func (g greeting) AddButton() { + log.Println("gui.gocui.AddButton()", name) + addButton(name) +} + +func addButton(name string) error { t := len(name) v, err := baseGui.SetView(name, currentX, currentY, currentX+t+3, currentY+2, 0) if err == nil { diff --git a/toolkit/gocui/main.go b/toolkit/gocui/main.go index 2439a3a..314f5be 100644 --- a/toolkit/gocui/main.go +++ b/toolkit/gocui/main.go @@ -50,18 +50,18 @@ func Init() { log.Panicln(err) } - AddButton("hello") - AddButton("world") - AddButton("foo") + addButton("hello") + addButton("world") + addButton("foo") - AddGroup("blank") - AddButton("bar") - AddButton("bar none") - AddButton("bar going") + addGroup("blank") + addButton("bar") + addButton("bar none") + addButton("bar going") - AddGroup("te") - AddButton("world 2") - AddButton("foo 2") + addGroup("te") + addButton("world 2") + addButton("foo 2") if err := baseGui.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { log.Panicln(err) diff --git a/toolkit/gocui/newJ.go b/toolkit/gocui/newJ.go index 47c7439..3e04cd3 100644 --- a/toolkit/gocui/newJ.go +++ b/toolkit/gocui/newJ.go @@ -20,7 +20,7 @@ var bottomY int = 7 func newJ(g *gocui.Gui) error { // maxX, maxY := g.Size() - name := fmt.Sprintf("jcarr %v test ", idxView) + name := fmt.Sprintf("jcarr %v foo ", idxView) v, err := g.SetView(name, topX, topY, bottomX, bottomY, 0) if err == nil { return err