gocui: log() output works

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2023-04-26 20:56:25 -05:00
parent af41bdfc59
commit 4e8a1bc432
11 changed files with 136 additions and 35 deletions

View File

@ -139,7 +139,7 @@ Creates a window helpful for debugging this package
`func ShowDebugValues()` `func ShowDebugValues()`
### func [StandardExit](/main.go#L182) ### func [StandardExit](/main.go#L191)
`func StandardExit()` `func StandardExit()`
@ -180,7 +180,7 @@ var Config GuiConfig
The Node is a binary tree. This is how all GUI elements are stored The Node is a binary tree. This is how all GUI elements are stored
simply the name and the size of whatever GUI element exists simply the name and the size of whatever GUI element exists
#### func [New](/main.go#L153) #### func [New](/main.go#L162)
`func New() *Node` `func New() *Node`

View File

@ -19,6 +19,7 @@ package witlog
// //
import ( import (
"io"
"os" "os"
"runtime" "runtime"
"runtime/pprof" "runtime/pprof"
@ -152,8 +153,8 @@ func logindent(depth int, format string, a ...interface{}) {
Log(debugToolkit, newFormat, a) Log(debugToolkit, newFormat, a)
} }
func SetOutput(f *os.File) { func SetOutput(w io.Writer) {
golog.SetOutput(f) golog.SetOutput(w)
} }
func SetToolkitOutput(newLog func(...any)) { func SetToolkitOutput(newLog func(...any)) {

View File

@ -40,6 +40,9 @@ func init() {
Config.flag = Config.rootNode.newNode("flag", 0, nil) Config.flag = Config.rootNode.newNode("flag", 0, nil)
Config.flag.WidgetType = toolkit.Flag Config.flag.WidgetType = toolkit.Flag
Config.flag = Config.rootNode.newNode("stdout", 0, nil)
Config.flag.WidgetType = toolkit.Stdout
Config.guiChan = make(chan toolkit.Action, 1) Config.guiChan = make(chan toolkit.Action, 1)
go watchCallback() go watchCallback()
} }
@ -51,6 +54,12 @@ func watchCallback() {
select { select {
case a := <-Config.guiChan: case a := <-Config.guiChan:
n := Config.rootNode.FindId(a.WidgetId) n := Config.rootNode.FindId(a.WidgetId)
if (a.ActionType == toolkit.UserQuit) {
log(logNow, "doUserEvent() node =", n.id, n.Name, "User sent Quit()")
n.doCustom()
exit("wit/gui toolkit.UserQuit")
break
}
if (n == nil) { if (n == nil) {
log(logError, "watchCallback() UNKNOWN widget id =", a.WidgetId, a.Name) log(logError, "watchCallback() UNKNOWN widget id =", a.WidgetId, a.Name)
} else { } else {

View File

@ -1,8 +1,8 @@
package main package main
import ( import (
"fmt" // "fmt"
"errors" // "errors"
"strconv" "strconv"
"strings" "strings"
@ -178,7 +178,7 @@ func (w *cuiWidget) drawTree(draw bool) {
} }
func click(g *gocui.Gui, v *gocui.View) error { func click(g *gocui.Gui, v *gocui.View) error {
var l string // var l string
var err error var err error
log(logNow, "click() START", v.Name()) log(logNow, "click() START", v.Name())
@ -201,6 +201,7 @@ func click(g *gocui.Gui, v *gocui.View) error {
return err return err
} }
/*
_, cy := v.Cursor() _, cy := v.Cursor()
if l, err = v.Line(cy); err != nil { if l, err = v.Line(cy); err != nil {
l = "" l = ""
@ -213,6 +214,7 @@ func click(g *gocui.Gui, v *gocui.View) error {
v.SelFgColor = gocui.ColorBlack v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, l) fmt.Fprintln(v, l)
} }
*/
// this seems to delete the button(?) // this seems to delete the button(?)
// g.SetViewOnBottom(v.Name()) // g.SetViewOnBottom(v.Name())

View File

@ -76,13 +76,13 @@ func addDebugKeys(g *gocui.Gui) {
g.SetKeybinding("", 'q', gocui.ModNone, g.SetKeybinding("", 'q', gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
me.baseGui.Close() me.baseGui.Close()
exit("forced exit() from within gocui") sendBackQuit()
return nil return nil
}) })
g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error { func(g *gocui.Gui, v *gocui.View) error {
me.baseGui.Close() me.baseGui.Close()
exit("forced exit() from within gocui") sendBackQuit()
return nil return nil
}) })

View File

@ -1,9 +1,9 @@
package main package main
import ( import (
"fmt" "io"
"os" // "fmt"
"strings" // "strings"
witlog "git.wit.org/wit/gui/log" witlog "git.wit.org/wit/gui/log"
) )
@ -29,6 +29,7 @@ func exit(a ...any) {
witlog.Exit(a...) witlog.Exit(a...)
} }
/*
func newLog(a ...any) { func newLog(a ...any) {
s := fmt.Sprint(a...) s := fmt.Sprint(a...)
tmp := strings.Split(s, "\n") tmp := strings.Split(s, "\n")
@ -44,8 +45,12 @@ func newLog(a ...any) {
} }
} }
} }
*/
func setOutput(f *os.File) { func setOutput(w io.Writer) {
witlog.SetOutput(f) if (w == nil) {
witlog.SetToolkitOutput(newLog) return
}
witlog.SetOutput(w)
// witlog.SetToolkitOutput(newLog)
} }

View File

@ -35,6 +35,12 @@ func PluginChannel() chan toolkit.Action {
return me.pluginChan return me.pluginChan
} }
/*
recieves requests from the program to do things like:
* add new widgets
* change the text of a label
* etc..
*/
func catchActionChannel() { func catchActionChannel() {
log(logInfo, "catchActionChannel() START") log(logInfo, "catchActionChannel() START")
for { for {
@ -55,21 +61,35 @@ func catchActionChannel() {
func Exit() { func Exit() {
// TODO: what should actually happen here? // TODO: what should actually happen here?
me.baseGui.Close() me.baseGui.Close()
sendBackQuit()
} }
func sendBackQuit() {
// send 'Quit' back to the program (?)
var a toolkit.Action
a.ActionType = toolkit.UserQuit
me.callback <- a
}
var outf *os.File
func main() { func main() {
var err error
log(logInfo, "main() start Init()") log(logInfo, "main() start Init()")
outf, err := os.OpenFile("/tmp/witgui.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) outf, err = os.OpenFile("/tmp/witgui.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil { if err != nil {
exit("error opening file: %v", err) exit("error opening file: %v", err)
} }
defer outf.Close() defer outf.Close()
setOutput(outf) // setOutput(outf)
log("This is a test log entry") // log("This is a test log entry")
MouseMain() MouseMain()
log(true, "MouseMain() closed") log(true, "MouseMain() closed")
me.baseGui.Close() me.baseGui.Close()
sendBackQuit()
} }

View File

@ -52,6 +52,9 @@ func layout(g *gocui.Gui) error {
if widgetView, _ := g.View("msg"); widgetView == nil { if widgetView, _ := g.View("msg"); widgetView == nil {
log(logInfo, "create output widget now", maxX, maxY, mx, my) log(logInfo, "create output widget now", maxX, maxY, mx, my)
makeOutputWidget(g, "this is a create before a mouse click") makeOutputWidget(g, "this is a create before a mouse click")
if (me.logStdout != nil) {
setOutput(me.logStdout)
}
} else { } else {
log(logInfo, "output widget already exists", maxX, maxY, mx, my) log(logInfo, "output widget already exists", maxX, maxY, mx, my)
} }

View File

@ -5,10 +5,11 @@ import (
"fmt" "fmt"
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit"
) )
var outputW int = 80 var outputW int = 200
var outputH int = 24 var outputH int = 36
func moveMsg(g *gocui.Gui) { func moveMsg(g *gocui.Gui) {
mx, my := g.MousePosition() mx, my := g.MousePosition()
@ -36,24 +37,62 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) { func makeOutputWidget(g *gocui.Gui, stringFromMouseClick string) *gocui.View {
maxX, maxY := g.Size() maxX, maxY := g.Size()
v, err := g.SetView("msg", maxX-32, maxY/2, maxX/2+outputW, maxY/2+outputH, 0)
if (me.rootNode == nil) {
// keep skipping this until the binary tree is initialized
return nil
}
if (me.logStdout == nil) {
a := new(toolkit.Action)
a.Name = "stdout"
a.Text = "stdout"
a.WidgetType = toolkit.Stdout
a.WidgetId = -3
a.ParentId = 0
me.logStdout = makeWidget(a)
me.logStdout.gocuiSize.w0 = maxX - 32
me.logStdout.gocuiSize.h0 = maxY/2
me.logStdout.gocuiSize.w1 = me.logStdout.gocuiSize.w0 + outputW
me.logStdout.gocuiSize.h1 = me.logStdout.gocuiSize.h0 + outputH
me.logStdout.realWidth = me.logStdout.gocuiSize.Width()
me.logStdout.realHeight = me.logStdout.gocuiSize.Height()
}
v, err := g.View("msg")
if (v == nil) {
log("this is supposed to happen. v == nil", err)
} else {
log("msg != nil. WTF now? err =", err)
}
// help, err := g.SetView("help", maxX-32, 0, maxX-1, 13, 0) // help, err := g.SetView("help", maxX-32, 0, maxX-1, 13, 0)
// v, err = g.SetView("msg", 3, 3, 30, 30, 0)
v, err = g.SetView("msg", maxX-32, maxY/2, maxX/2+outputW, maxY/2+outputH, 0)
if errors.Is(err, gocui.ErrUnknownView) { if errors.Is(err, gocui.ErrUnknownView) {
log("this is supposed to happen?", err) log("this is supposed to happen?", err)
} }
if (err != nil) { if (err != nil) {
log("create output window failed", err) log("create output window failed", err)
return // return nil
} }
v.Clear() if (v == nil) {
v.SelBgColor = gocui.ColorCyan log("msg == nil. WTF now? err =", err)
v.SelFgColor = gocui.ColorBlack return nil
} else {
me.logStdout.v = v
}
me.logStdout.v.Clear()
me.logStdout.v.SelBgColor = gocui.ColorCyan
me.logStdout.v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, "figure out how to capture STDOUT to here\n" + stringFromMouseClick) fmt.Fprintln(v, "figure out how to capture STDOUT to here\n" + stringFromMouseClick)
g.SetViewOnBottom("msg") g.SetViewOnBottom("msg")
// g.SetViewOnBottom(v.Name()) // g.SetViewOnBottom(v.Name())
return return v
} }

View File

@ -13,6 +13,7 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"sync" "sync"
"strings"
"github.com/awesome-gocui/gocui" "github.com/awesome-gocui/gocui"
"git.wit.org/wit/gui/toolkit" "git.wit.org/wit/gui/toolkit"
) )
@ -25,6 +26,8 @@ type config struct {
rootNode *cuiWidget // the base of the binary tree. it should have id == 0 rootNode *cuiWidget // the base of the binary tree. it should have id == 0
ctrlDown *cuiWidget // shown if you click the mouse when the ctrl key is pressed ctrlDown *cuiWidget // shown if you click the mouse when the ctrl key is pressed
current *cuiWidget // this is the current tab or window to show current *cuiWidget // this is the current tab or window to show
logStdout *cuiWidget // where to show STDOUT
logStdoutV *gocui.View // where to show STDOUT
// this is the channel we send user events like // this is the channel we send user events like
// mouse clicks or keyboard events back to the program // mouse clicks or keyboard events back to the program
@ -200,12 +203,27 @@ func (w *cuiWidget) Write(p []byte) (n int, err error) {
w.tainted = true w.tainted = true
w.writeMutex.Lock() w.writeMutex.Lock()
defer w.writeMutex.Unlock() defer w.writeMutex.Unlock()
if (w.v == nil) { if (me.logStdout.v == nil) {
fmt.Fprintln(outf, string(p))
v, _ := me.baseGui.View("msg")
if (v != nil) {
fmt.Fprintln(outf, "found msg")
me.logStdout.v = v
}
return return
} }
w.v.Clear() me.logStdout.v.Clear()
fmt.Fprintln(w.v, p) // fmt.Fprintln(w.v, p + "jcarr")
log(logNow, "widget.Write()", p) // log(logNow, "widget.Write()", p)
s := fmt.Sprint(string(p))
s = strings.TrimSuffix(s, "\n")
tmp := strings.Split(s, "\n")
outputS = append(outputS, tmp...)
if (len(outputS) > 50) {
outputS = outputS[10:]
}
fmt.Fprintln(me.logStdout.v, strings.Join(outputS, "\n"))
return len(p), nil return len(p), nil
} }
@ -221,20 +239,20 @@ func Set(ptr interface{}, tag string) error {
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
defaultVal := t.Field(i).Tag.Get(tag) defaultVal := t.Field(i).Tag.Get(tag)
// name := t.Field(i).Name name := t.Field(i).Name
// log("Set() try name =", name, "defaultVal =", defaultVal) // log("Set() try name =", name, "defaultVal =", defaultVal)
setField(v.Field(i), defaultVal) setField(v.Field(i), defaultVal, name)
} }
return nil return nil
} }
func setField(field reflect.Value, defaultVal string) error { func setField(field reflect.Value, defaultVal string, name string) error {
if !field.CanSet() { if !field.CanSet() {
// log("setField() Can't set value", field, defaultVal) // log("setField() Can't set value", field, defaultVal)
return fmt.Errorf("Can't set value\n") return fmt.Errorf("Can't set value\n")
} else { } else {
log("setField() Can set value", field, defaultVal) log("setField() Can set value", name, defaultVal)
} }
switch field.Kind() { switch field.Kind() {

View File

@ -69,6 +69,7 @@ const (
Font // TODO Font // TODO
Color // TODO Color // TODO
Dialog // TODO Dialog // TODO
Stdout // can be used to capture and display log output
) )
const ( const (
@ -93,6 +94,7 @@ const (
User // the user did something (mouse, keyboard, etc) User // the user did something (mouse, keyboard, etc)
InitToolkit // initializes the toolkit InitToolkit // initializes the toolkit
CloseToolkit // closes the toolkit CloseToolkit // closes the toolkit
UserQuit // the user closed the GUI
) )
func (s WidgetType) String() string { func (s WidgetType) String() string {
@ -141,6 +143,8 @@ func (s WidgetType) String() string {
return "Color" return "Color"
case Dialog: case Dialog:
return "Dialog" return "Dialog"
case Stdout:
return "Stdout"
case Unknown: case Unknown:
return "Unknown" return "Unknown"
} }