From c5472a42a24ff2ec0dce44c6ea275cd2670f8524 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 13 Feb 2025 14:11:52 -0600 Subject: [PATCH] finally starting to clean up the init() process --- eventBindings.go | 14 ++++ eventMouseDrag.go | 2 - help.go | 9 +++ init.go | 174 ++++++++++++++++++++-------------------------- stdoutShow.go | 39 +++++++---- structs.go | 6 +- 6 files changed, 127 insertions(+), 117 deletions(-) diff --git a/eventBindings.go b/eventBindings.go index f78737c..6e3f3a5 100644 --- a/eventBindings.go +++ b/eventBindings.go @@ -4,6 +4,7 @@ package main import ( + "fmt" "syscall" "time" @@ -16,6 +17,12 @@ import ( // tells 'gocui' where to send events func registerHandlers(g *gocui.Gui) { + defer func() { + if r := recover(); r != nil { + fmt.Fprintln(outf, "EVENT BINDINGS recovered in r", r) + return + } + }() // mouse handlers g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, mouseDown) // normal left mouse down @@ -56,8 +63,15 @@ func registerHandlers(g *gocui.Gui) { g.SetKeybinding("", 'q', gocui.ModNone, quit) // 'q' only exits gocui. plugin stays alive (?) time.Sleep(100 * time.Millisecond) + + fmt.Fprintln(outf, "hello world", time.Since(me.starttime)) + + // coreStdout() + // createStdout(g) // tell 'tree' that we are okay to start talking to me.myTree.InitOK() + me.ok = true // this tells init() it's okay to work with gocui + } // flips on 'super mouse' mode // this was awesome for debugging gocui. never remove this code. diff --git a/eventMouseDrag.go b/eventMouseDrag.go index 137e421..4f4239a 100644 --- a/eventMouseDrag.go +++ b/eventMouseDrag.go @@ -23,8 +23,6 @@ import ( // this function uses the mouse position to highlight & unhighlight things // this is run every time the user moves the mouse over the terminal window func mouseMove(g *gocui.Gui) { - me.ok = true // this tells init() it's okay to work with gocui - // this runs while the user moves the mouse. this highlights text // toggle off all highlight views except for whatever is under the mouse // START HIGHLIGHTING diff --git a/help.go b/help.go index f0cf48b..a0b638a 100644 --- a/help.go +++ b/help.go @@ -131,6 +131,15 @@ func setThingsOnTop() { me.baseGui.SetViewOnTop(me.clock.tk.v.Name()) } + if me.stdout.tk == nil { + makeOutputWidget(me.baseGui, "from setThingsOnTop()") + } + if me.stdout.tk == nil { + return + } + if me.stdout.tk.v == nil { + return + } if me.dark { me.stdout.tk.v.FgColor = gocui.ColorWhite me.stdout.tk.v.BgColor = gocui.ColorBlack diff --git a/init.go b/init.go index 3adaf1b..646aee0 100644 --- a/init.go +++ b/init.go @@ -9,6 +9,7 @@ package main import ( "errors" + "fmt" "os" "runtime" "runtime/debug" @@ -31,6 +32,21 @@ func toolkitClose() { // sets defaults and establishes communication // to this toolkit from the wit/gui golang package func initPlugin() { + defer func() { + if r := recover(); r != nil { + fmt.Fprintf(outf, "PANIC: initPlugin() recovered %v\n", r) + return + } + }() + + var err error + // todo: make this a tmp file that goes away + outf, err = os.OpenFile("/tmp/captureMode.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Info("error opening file:", err) + os.Exit(0) + } + me.starttime = time.Now() log.Log(INFO, "Init() of awesome-gocui") // init the config struct default values @@ -86,16 +102,59 @@ func initPlugin() { } log.Log(NOW, "Init() start pluginChan") - // log.Sleep(.1) // probably not needed, but in here for now under development - go mainGogui() - // log.Sleep(.1) // probably not needed, but in here for now under development + + os.Stdout = outf + + log.CaptureMode(outf) + + // init gocui + g, err := gocui.NewGui(gocui.OutputNormal, true) + if err != nil { + return + } + me.baseGui = g + g.Cursor = true + g.Mouse = true + + // this sets the function that is run on every event. For example: + // When you click the mouse, move the mouse, or press a key on the keyboard + // This is equivalent to xev or similar to cat /dev/input on linux + g.SetManagerFunc(gocuiEvent) + + // register how the 'gocui' will work as a GO toolkit plugin + // all applications will use these keys. they are universal. + // registered event handlers still have the events sent to gocuiEvent() above + registerHandlers(g) + + go gocuiMain() +} + +// This goroutine sits in gocui's MainLoop() +func gocuiMain() { + defer func() { + if r := recover(); r != nil { + log.Warn("PANIC ecovered in gocuiMain()", r) + fmt.Fprintf(outf, "PANIC recovered in r = %v", r) + os.Stderr = outf + os.Stdout = outf + debug.PrintStack() + panic(outf) + } + }() + + // me.stdout.Write([]byte("begin gogui.MainLoop()\n")) + if err := me.baseGui.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { + log.Log(NOW, "g.MainLoop() panic err =", err) + // normally panic here + panic("gocuiTKmainloop OOPS") + } } func standardExit() { log.Log(NOW, "standardExit() doing baseGui.Close()") me.baseGui.Close() log.Log(NOW, "standardExit() doing outf.Close()") - me.outf.Close() + outf.Close() // log(true, "standardExit() setOutput(os.Stdout)") // setOutput(os.Stdout) log.Log(NOW, "standardExit() send back Quit()") @@ -110,7 +169,7 @@ func standardClose() { log.Log(NOW, "standardExit() doing baseGui.Close()") me.baseGui.Close() log.Log(NOW, "standardExit() doing outf.Close()") - me.outf.Close() + outf.Close() // os.Stdin = os.Stdin // os.Stdout = os.Stdout // os.Stderr = os.Stderr @@ -120,101 +179,15 @@ func standardClose() { func main() { } -var origStdout *os.File -var origStderr *os.File - -func mainGogui() { - defer func() { - if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in guiMain application:", r) - log.Warn("Recovered from panic:", r) - me.baseGui.Close() - log.CaptureMode(nil) - log.Warn("YAHOOOO Recovered in guiMain application:", r) - log.Warn("Recovered from panic:", r) - me.myTree.SendToolkitPanic() - - return - } - }() - - var err error - - // todo: make this a tmp file that goes away - me.outf, err = os.OpenFile("/tmp/captureMode.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - log.Info("error opening file:", err) - os.Exit(0) - } - origStdout = os.Stdout - os.Stdout = me.outf - defer me.outf.Close() - - log.CaptureMode(me.outf) - - gocuiMain() -} - -// This initializes the gocui package -// it runs SetManagerFunc which passes every input -// event (keyboard, mouse, etc) to the function "gocuiEvent()" -func gocuiMain() { - defer func() { - if r := recover(); r != nil { - log.Warn("YAHOOOO Recovered in gocuiMain()", r) - log.Warn("Recovered from panic:", r) - me.baseGui.Close() - - // allow gocui to close if possible, then print stack - log.Sleep(1) - os.Stdout = origStdout - os.Stderr = origStderr - me.myTree.SendToolkitPanic() - log.Warn("Stack trace:") - debug.PrintStack() - // panic("BUMMER 2") - - // attempt to switch to the nocui toolkit - log.Sleep(1) - me.myTree.SendToolkitLoad("nocui") - log.Sleep(3) - me.myTree.SendToolkitLoad("nocui") - // panic("BUMMER") - return - } - }() - g, err := gocui.NewGui(gocui.OutputNormal, true) - if err != nil { - return - } - defer g.Close() - - me.baseGui = g - - g.Cursor = true - g.Mouse = true - - // this sets the function that is run on every event. For example: - // When you click the mouse, move the mouse, or press a key on the keyboard - // This is equivalent to xev or similar to cat /dev/input on linux - g.SetManagerFunc(gocuiEvent) - - // register how the 'gocui' will work as a GO toolkit plugin - // all applications will use these keys. they are universal. - // registered event handlers still have the events sent to gocuiEvent() above - registerHandlers(g) - - // me.stdout.Write([]byte("begin gogui.MainLoop()\n")) - if err := g.MainLoop(); err != nil && !errors.Is(err, gocui.ErrQuit) { - log.Log(NOW, "g.MainLoop() panic err =", err) - // normally panic here - panic("gocuiTKmainloop OOPS") - } -} - // this hack is to wait for the application to send something // before trying to do anything. todo: rethink this someday func waitOK() { + defer func() { + if r := recover(); r != nil { + fmt.Fprintln(outf, "INIT PLUGIN recovered in r", r) + return + } + }() for { if me.ok { return @@ -231,6 +204,12 @@ func testRefresh(*gocui.Gui) error { // refresh the screen 10 times a second func refreshGocui() { + defer func() { + if r := recover(); r != nil { + fmt.Fprintln(outf, "INIT PLUGIN recovered in r", r) + return + } + }() var lastRefresh time.Time lastRefresh = time.Now() for { @@ -286,6 +265,7 @@ func newWindowTrigger() { // log.Log(NOW, "newWindowTrigger() got new window", tk.cuiName) time.Sleep(200 * time.Millisecond) waitOK() + time.Sleep(200 * time.Millisecond) redoWindows(3, 3) if !me.stdout.init { me.stdout.init = true diff --git a/stdoutShow.go b/stdoutShow.go index fbc94f2..38fc837 100644 --- a/stdoutShow.go +++ b/stdoutShow.go @@ -32,28 +32,36 @@ func createStdout(g *gocui.Gui) bool { return true } +func coreStdout() { + if me.stdout.tk != nil { + return + } + a := new(widget.Action) + a.ProgName = "2stdout2" + a.WidgetType = widget.Stdout + a.WidgetId = me.stdout.wId + a.ParentId = 0 + // n := addNode(a) + n := me.myTree.AddNode(a) + me.stdout.tk = initWidget(n) + + tk := me.stdout.tk + tk.gocuiSize.w0 = me.stdout.lastW + tk.gocuiSize.h0 = me.stdout.lastH + tk.gocuiSize.w1 = tk.gocuiSize.w0 + me.stdout.w + tk.gocuiSize.h1 = tk.gocuiSize.h0 + me.stdout.h +} + func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View { if me.treeRoot == nil { // keep skipping this until the binary tree is initialized return nil } + coreStdout() + if me.stdout.tk == nil { - a := new(widget.Action) - a.ProgName = "2stdout2" - a.WidgetType = widget.Stdout - a.WidgetId = me.stdout.wId - a.ParentId = 0 - // n := addNode(a) - n := me.myTree.AddNode(a) - me.stdout.tk = initWidget(n) - - tk := me.stdout.tk - tk.gocuiSize.w0 = me.stdout.lastW - tk.gocuiSize.h0 = me.stdout.lastH - tk.gocuiSize.w1 = tk.gocuiSize.w0 + me.stdout.w - tk.gocuiSize.h1 = tk.gocuiSize.h0 + me.stdout.h - + return nil } v, err := g.View("msg") @@ -61,6 +69,7 @@ func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View { log.Log(NOW, "makeoutputwindow() this is supposed to happen. v == nil", err) } else { log.Log(NOW, "makeoutputwindow() msg != nil. WTF now? err =", err) + return v } rect := me.stdout.tk.gocuiSize diff --git a/structs.go b/structs.go index e9cfc8f..af5fb41 100644 --- a/structs.go +++ b/structs.go @@ -22,7 +22,8 @@ import ( "go.wit.com/toolkits/tree" ) -var initOnce sync.Once +var initOnce sync.Once // run initPlugin() only once +var outf *os.File // hacks for capturing stdout // It's probably a terrible idea to call this 'me' // 2025 note: doesn't seem terrible to call this 'me' anymore. notsure. @@ -77,8 +78,7 @@ type config struct { mouse mouse // mouse settings showDebug bool // todo: move this into config struct debug bool // todo: move this into config struct - outf *os.File // hacks for capturing stdout - + starttime time.Time // checks how long it takes on startup } // stuff controlling how the mouse works