package main import ( "bytes" "fmt" "log" "os" "red-green/door" "runtime/debug" "runtime/pprof" "time" // "net/http" // _ "net/http/pprof" ) const ENABLE_PROFILER bool = false // "runtime/pprof" // Max X value we can use before hitting MemStats panel. var MaxX int = 0 func press_keys(d *door.Door) { d.WriteA(door.Reset, door.CRNL, "Press some keys... to exit.") var r rune var ex door.Extended var err error for (r != 0x0d) && (err == nil) { r, ex, err = d.WaitKey(door.Inactivity) if ex == door.MOUSE { m, ok := d.GetMouse() if ok { // var m door.MouseInfo = door.Mouse d.WriteA(fmt.Sprintf("M %d (%d,%d) ", m.Button, m.X, m.Y)) } } else { if ex == door.NOP { d.WriteA(fmt.Sprintf("%d (%x) ", r, r)) } else { d.WriteA(fmt.Sprintf("<%s> ", ex.String())) } } } d.WriteA(door.Reset, door.CRNL) } func press_key_or_mouse(d *door.Door) error { var err error var ex door.Extended for { _, ex, err = d.WaitKey(door.Inactivity) if err != nil { return err } if ex == door.MOUSE { m, ok := d.GetMouse() if ok { if m.Button == 1 { break } } } else { break } } return nil } func press_a_key(d *door.Door) error { var err error // var ex door.Extended d.WriteA(door.Reset, door.CRNL, "Press a key, or LEFT mouse click to continue...") /* for { _, ex, err = d.WaitKey(door.Inactivity) if ex == door.MOUSE { m, ok := d.GetMouse() if ok { if m.Button == 1 { break } } } else { break } } */ err = press_key_or_mouse(d) d.WriteA(door.CRNL) return err } func main() { var message string if ENABLE_PROFILER { fp1, err1 := os.Create("cpu.pro") if err1 != nil { log.Fatal(err1) } pprof.StartCPUProfile(fp1) defer pprof.StopCPUProfile() defer func() { fp2, err2 := os.Create("memory.pro") if err2 != nil { log.Fatal(err2) } pprof.WriteHeapProfile(fp2) }() } /* go func() { http.ListenAndServe(":6060", nil) }() */ var d door.Door = door.Door{} d.Init("testdoor") defer func() { if err := recover(); err != nil { // This displays stack trace stderr debug.PrintStack() fmt.Println("ERROR:", err) log.Println("FAILURE:", err) // Display error to user d.WriteA(fmt.Sprintf(door.Reset+door.CRNL+"Exception: %v"+door.CRNL, err)) } }() defer d.Close() // Updaters work best when the screen doesn't scroll, so start // us off at the very top. d.WriteA(door.Clrscr) // Start spinrite effects var ticker *time.Ticker = time.NewTicker(time.Millisecond * time.Duration(100)) // 100 var spin door.SpinRiteMsg = door.SpinRiteMsgInit(15, 5, door.ColorText("RED ON GREEN"), []string{"RED", "GREEN", "SOFTWARE"}) /* var spin2 door.SpinRite = door.SpinRiteInit(13, 5, door.ColorText("BRI CYA ON BLUE")) */ // Add in the GoRoutine Status panel MaxX = door.Width - 20 var goPanel door.Panel = door.Panel{X: door.Width - 19, Y: 3, Width: 16, Style: door.DOUBLE, Title: "] GoRuntime [", BorderColor: door.ColorText("BOLD YELL"), } const DisplayGoRoutines bool = true if DisplayGoRoutines { goLineUpdater := func(u *bytes.Buffer) { u.Reset() u.Write(GoRoutinesStatus()) // log.Println(status) } var goLine *door.Line = &door.Line{ Text: &bytes.Buffer{}, UpdateF: goLineUpdater, Width: goPanel.Width, DefaultColor: door.ColorText("CYAN"), } // goLine.Update() // Force Update goPanel.Lines = append(goPanel.Lines, goLine) } // Display Legend on GoRuntime panel const DisplayGoRoutineLegend bool = false // Display Memory const DisplayMemory bool = true var MemoryStats map[string]*bytes.Buffer = make(map[string]*bytes.Buffer) if DisplayGoRoutineLegend { // Line for legend. goPanel.Lines = append(goPanel.Lines, &door.Line{Width: goPanel.Width}) } if DisplayMemory { memColor := door.ColorText("BRI BLUE") memoryUpdater := func(u *bytes.Buffer) { if u == nil { u = &bytes.Buffer{} } u.Reset() Memory(&MemoryStats) fmt.Fprintf(u, "%-8s%8s", "Sys", MemoryStats["Sys"].Bytes()) } // memoryUpdater(&bytes.Buffer{}) goPanel.Lines = append(goPanel.Lines, &door.Line{UpdateF: memoryUpdater, Width: goPanel.Width, DefaultColor: memColor}) heapUpdater := func(u *bytes.Buffer) { if u == nil { u = &bytes.Buffer{} } u.Reset() fmt.Fprintf(u, "%-8s%8s", "HeapSys", MemoryStats["Heap"].Bytes()) } goPanel.Lines = append(goPanel.Lines, &door.Line{UpdateF: heapUpdater, Width: goPanel.Width, DefaultColor: memColor}) stackUpdater := func(u *bytes.Buffer) { u.Reset() fmt.Fprintf(u, "%-8s%8s", "StackSys", MemoryStats["StackSys"].Bytes()) } goPanel.Lines = append(goPanel.Lines, &door.Line{UpdateF: stackUpdater, Width: goPanel.Width, DefaultColor: memColor}) gcUpdater := func(u *bytes.Buffer) { u.Reset() fmt.Fprintf(u, "%-8s%8s", "NumGC", MemoryStats["NumGC"].Bytes()) } goPanel.Lines = append(goPanel.Lines, &door.Line{UpdateF: gcUpdater, Width: goPanel.Width, DefaultColor: memColor}) } var lIndex int = 0 var legendCount int = 0 const legendUpdate = 20 go func() { defer func() { r := recover() if r != nil { log.Printf("** FAIL: %s, %#v\n", r, r) } }() // var output string var legend []string = []string{ "R=run r=Runnable", "S=Select s=Syscall", "Chan write", "Z=Sleep P=Preempt", "I=Idle D=Dead", "W=Wait C=Copystk", } if DisplayGoRoutineLegend { goPanel.Lines[1].Text = bytes.NewBuffer([]byte(legend[0])) } for range ticker.C { // output = door.SavePos + door.Goto(door.Width-16, 1) + spin.Output() + // door.Goto(door.Width-15, 3) + spin2.Output() + door.RestorePos if DisplayGoRoutineLegend { legendCount++ if legendCount >= legendUpdate { legendCount = 0 lIndex++ if lIndex == len(legend) { lIndex = 0 } goPanel.Lines[1].Text = bytes.NewBuffer([]byte(legend[lIndex])) } } if goPanel.X == 0 { goPanel.X = door.Width - 40 } goPanel.Update() //output = door.Goto(door.Width-16, 1) + spin.Output() + goPanel.Output() /* + door.Goto(door.Width-15, 3) + spin2.Output() */ if !d.Disconnect() { // d.Update(output) d.WriteA(door.SavePos, door.Goto(door.Width-16, 1), spin.Output(), goPanel.Output(), door.RestorePos) } else { log.Println("Ticker.Stop: Disconnected!") ticker.Stop() return } } log.Println("range Ticker.C stopped.") }() var wopr door.WOPR wopr.Init(d.StartTime, d.TimeOut, []byte{}) wopr.ElapsedPanel.X = door.Width - 19 wopr.ElapsedPanel.Y = door.Height - 15 wopr.RemainingPanel.X = door.Width - 19 wopr.RemainingPanel.Y = door.Height - 8 wopr.Animate(&d) // bold := door.Color(1, 37, 40) var bolder = door.ColorText("BOLD YEL ON BLUE") d.WriteA("Welcome to ", bolder, "go door go TestDoor.", door.Reset, door.CRNL, "...", door.CRNL) d.EnableMouse(door.Normal) press_a_key(&d) d.WriteA(door.CRNL) var b []string if door.CP437 { b = door.AlertBox("Alert: go \xfb is in use!", 1) } else { b = door.AlertBox("Alert: go \u221a is in use!", 1) } warningColor := door.ColorText("BRI WHI ON GREEN") for _, line := range b { // Prevent color bleeding. d.WriteA(warningColor, line, door.Reset, door.CRNL) } d.WriteA(door.Reset, door.CRNL) var left time.Duration = d.TimeLeft() message = fmt.Sprintf("You have %0.2f minutes / %0.2f seconds remaining..."+door.CRNL, left.Minutes(), left.Seconds()) d.WriteA(message) press_a_key(&d) var mainmenu door.Menu = MainMenu() var choice int for choice >= 0 { d.WriteA(door.Clrscr, door.HideCursor) choice = mainmenu.Choose(&d) d.WriteA(door.ShowCursor) if choice < 0 { break } option := mainmenu.GetOption(choice) wopr.Stop() // Clear WOPR panels. d.WriteA(door.Reset, wopr.Clear()) r, b := mainmenu.Panel.RightBottomPos() d.WriteA(door.Goto(r, b)) // fmt.Printf("Choice: %d, Option: %c\n", choice, option) switch option { case 'A': display_ansi(&d) press_a_key(&d) case 'D': display_information(&d) press_a_key(&d) case 'F': font_demo(&d) press_a_key(&d) case 'I': d.WriteA(door.Reset, door.CRNL, door.CRNL) input_demo(&d) press_a_key(&d) case 'M': // Why is this so far down on the screen? (Scrolls) d.WriteA(door.Reset, door.CRNL, "TO DO: Provide menu of options to select from...", door.CRNL) press_a_key(&d) case 'P': progress_bars(&d) press_a_key(&d) case 'S': panel_demo(&d) press_a_key(&d) case 'T': about_test_door(&d) press_a_key(&d) case 'W': width_demo(&d) case 'Q': // This is also far down on the screen ... choice = -1 case 'C': // Disabled var a, z int z = 0 a = 10 / z z = a _ = a _ = z } wopr.Animate(&d) } // d.Write("\x1b[?1000l") // disable mouse // d.Write("\x1b[?1002l") d.DisableMouse() d.WriteA(door.Reset, door.CRNL) if d.Config.BBSID != "" { message = fmt.Sprintf("Returning to the %s BBS..."+door.CRNL, d.Config.BBSID) } else { message = "Returning to the BBS..." + door.CRNL } d.WriteA(message) d.WaitKey(time.Second) left = d.TimeLeft() ticker.Stop() message = fmt.Sprintf("You had %0.2f minutes remaining!"+door.CRNL, left.Minutes()) d.WriteA(message) left = d.TimeUsed() d.WriteA(fmt.Sprintf("You used %0.2f seconds / %0.2f minutes."+door.CRNL, left.Seconds(), left.Minutes())) fmt.Println("Ending testdoor.go") }