func main() { flag.Parse() if err := termui.Init(); err != nil { panic(err) } defer termui.Close() ticker := time.NewTicker(15 * time.Second) go func() { for { mstats, err := fetch.FetchMemStats(*target) if err != nil { termui.StopLoop() log.Fatal(err) } render(*mstats) <-ticker.C } }() termui.Handle("/sys/kbd/q", func(termui.Event) { // press q to quit termui.StopLoop() }) termui.Loop() }
//doLiveGraph builds a graph in the terminal window that //updates every graphUpdate seconds //It will build up to maxGraphs graphs with one time-series //per graph func doLiveGraph(res *wavefront.QueryResponse, query *wavefront.Querying, period int64) { err := ui.Init() if err != nil { log.Fatal(err) } defer ui.Close() if maxGraphs > len(res.TimeSeries) { maxGraphs = len(res.TimeSeries) } var wDivisor, hDivisor int switch maxGraphs { case 1: wDivisor = 1 hDivisor = 1 case 2: wDivisor = 2 hDivisor = 1 case 3, 4: wDivisor = 2 hDivisor = 2 } height := ui.TermHeight() / hDivisor width := ui.TermWidth() / wDivisor xVals, yVals := calculateCoords(maxGraphs, ui.TermWidth()/wDivisor, ui.TermHeight()/hDivisor) graphs := buildGraphs(res, height, width, xVals, yVals) ui.Render(graphs...) ui.Handle("/sys/kbd/q", func(ui.Event) { // press q to quit ui.StopLoop() }) ui.Handle("/sys/kbd/C-c", func(ui.Event) { // handle Ctrl + c combination ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { query.SetEndTime(time.Now()) query.SetStartTime(period) res, err := query.Execute() if err != nil { log.Fatal(err) } graphs := buildGraphs(res, height, width, xVals, yVals) ui.Render(graphs...) }) ui.Loop() }
func (m *Monitor) Start(conn *net.Conn) { if err := ui.Init(); err != nil { panic(err) } defer ui.Close() help := ui.NewPar(":PRESS q TO QUIT") help.Height = 3 help.Width = 50 help.TextFgColor = ui.ColorWhite help.BorderLabel = "Help" help.BorderFg = ui.ColorCyan // build ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, help), ), ) draw := func(t int) { ui.Body.Align() ui.Render(ui.Body) } draw(0) ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { t := e.Data.(ui.EvtTimer) draw(int(t.Count)) }) ui.Loop() }
func main() { if err := termui.Init(); err != nil { panic(err) } defer termui.Close() bc := termui.NewBarChart() data := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6} bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} bc.BorderLabel = "Bar Chart" bc.Data = data bc.Width = 26 bc.Height = 10 bc.DataLabels = bclabels bc.TextColor = termui.ColorGreen bc.BarColor = termui.ColorRed bc.NumColor = termui.ColorYellow termui.Render(bc) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() p := ui.NewPar("Press q to QUIT THE DEMO. [There](fg-blue) are other things [that](fg-red) are going to fit in here I think. What do you think? Now is the time for all good [men to](bg-blue) come to the aid of their country. [This is going to be one really really really long line](fg-green) that is going to go together and stuffs and things. Let's see how this thing renders out.\n Here is a new paragraph and stuffs and things. There should be a tab indent at the beginning of the paragraph. Let's see if that worked as well.") p.WrapLength = 48 // this should be at least p.Width - 2 p.Height = 20 p.Width = 50 p.Y = 2 p.X = 20 p.TextFgColor = ui.ColorWhite p.BorderLabel = "Text Box with Wrapping" p.BorderFg = ui.ColorCyan //p.Border = false ui.Render(p) ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Loop() }
func BuildUI() { ui.Init() defer ui.Close() receiveBox := CreateReceiveBox() sendBox := CreateSendBox() ui.Body.AddRows( ui.NewRow(ui.NewCol(12, 0, receiveBox)), ui.NewRow(ui.NewCol(12, 0, sendBox)), ) ui.Body.Align() ui.Render(ui.Body) ui.Handle("/sys/kbd/C-x", func(e ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { ReceiveBoxHeight = ui.TermHeight() - SendBoxHeight receiveBox.Height = ReceiveBoxHeight ui.Body.Align() ui.Render(ui.Body) }) // Leaving this commented out for now // I'd like to get this method of screen refreshing working instead of the 1s method, // but this crashes on resize. // ui.Handle("/sys/wnd/resize", func(e ui.Event) { // ui.Body.Align() // ui.Render(ui.Body) // }) ui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") strs := []string{ "[0] github.com/gizak/termui", "[1] [你好,世界](fg-blue)", "[2] [こんにちは世界](fg-red)", "[3] [color output](fg-white,bg-green)", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"} ls := termui.NewList() ls.Items = strs ls.ItemFgColor = termui.ColorYellow ls.BorderLabel = "List" ls.Height = 7 ls.Width = 25 ls.Y = 0 termui.Render(ls) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} spl0 := termui.NewSparkline() spl0.Data = data[3:] spl0.Title = "Sparkline 0" spl0.LineColor = termui.ColorGreen // single spls0 := termui.NewSparklines(spl0) spls0.Height = 2 spls0.Width = 20 spls0.Border = false spl1 := termui.NewSparkline() spl1.Data = data spl1.Title = "Sparkline 1" spl1.LineColor = termui.ColorRed spl2 := termui.NewSparkline() spl2.Data = data[5:] spl2.Title = "Sparkline 2" spl2.LineColor = termui.ColorMagenta // group spls1 := termui.NewSparklines(spl0, spl1, spl2) spls1.Height = 8 spls1.Width = 20 spls1.Y = 3 spls1.BorderLabel = "Group Sparklines" spl3 := termui.NewSparkline() spl3.Data = data spl3.Title = "Enlarged Sparkline" spl3.Height = 8 spl3.LineColor = termui.ColorYellow spls2 := termui.NewSparklines(spl3) spls2.Height = 11 spls2.Width = 30 spls2.BorderFg = termui.ColorCyan spls2.X = 21 spls2.BorderLabel = "Tweeked Sparkline" termui.Render(spls0, spls1, spls2) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func handleBackKey() { if obj, ok := currentPage.(GoBacker); ok { obj.GoBack() } else { ui.StopLoop() exitNow = true } }
func main() { if len(os.Args) < 2 { log.Fatal("Usage: ", os.Args[0], " <sparkyfish server hostname/IP>[:port]") } dest := os.Args[1] i := last(dest, ':') if i < 0 { dest = fmt.Sprint(dest, ":7121") } // Initialize our screen err := termui.Init() if err != nil { panic(err) } if termui.TermWidth() < 60 || termui.TermHeight() < 28 { fmt.Println("sparkyfish needs a terminal window at least 60x28 to run.") os.Exit(1) } defer termui.Close() // 'q' quits the program termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) // 'Q' also works termui.Handle("/sys/kbd/Q", func(termui.Event) { termui.StopLoop() }) sc := newsparkyClient() sc.serverHostname = dest sc.prepareChannels() sc.wr = newwidgetRenderer() // Begin our tests go sc.runTestSequence() termui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") sinps := (func() []float64 { n := 220 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/5) } return ps })() lc0 := termui.NewLineChart() lc0.BorderLabel = "braille-mode Line Chart" lc0.Data = sinps lc0.Width = 50 lc0.Height = 12 lc0.X = 0 lc0.Y = 0 lc0.AxesColor = termui.ColorWhite lc0.LineColor = termui.ColorGreen | termui.AttrBold lc1 := termui.NewLineChart() lc1.BorderLabel = "dot-mode Line Chart" lc1.Mode = "dot" lc1.Data = sinps lc1.Width = 26 lc1.Height = 12 lc1.X = 51 lc1.DotStyle = '+' lc1.AxesColor = termui.ColorWhite lc1.LineColor = termui.ColorYellow | termui.AttrBold lc2 := termui.NewLineChart() lc2.BorderLabel = "dot-mode Line Chart" lc2.Mode = "dot" lc2.Data = sinps[4:] lc2.Width = 77 lc2.Height = 16 lc2.X = 0 lc2.Y = 12 lc2.AxesColor = termui.ColorWhite lc2.LineColor = termui.ColorCyan | termui.AttrBold termui.Render(lc0, lc1, lc2) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func (s *Stats) Start() { s.cfUI.Say("Starting Stats...") err := termui.Init() if err != nil { s.cfUI.Warn(err.Error()) return } defer termui.Close() go func() { sinkTypeChart := &charts.SinkTypeChart{} sinkTypeChart.Init(s.cfUI) uaaChart := &charts.UAAChart{} uaaChart.Init(s.cfUI) msgLossChart := &charts.MsgLossChart{} msgLossChart.Init(s.cfUI) notesChart := &charts.NotesChart{} notesChart.Init() s.client.Sift( []charts.Chart{ sinkTypeChart, uaaChart, msgLossChart, }, ) termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, sinkTypeChart), termui.NewCol(6, 0, uaaChart), ), termui.NewRow( termui.NewCol(6, 0, msgLossChart), termui.NewCol(6, 0, notesChart), ), ) for { termui.Body.Align() termui.Render(termui.Body) time.Sleep(1 * time.Second) } }() termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() sinps := (func() []float64 { n := 220 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/5) } return ps })() p := termui.NewPar(":PRESS q or Esc TO QUIT DEMO Hello World") p.Height = 3 p.Width = 50 p.TextFgColor = termui.ColorWhite p.BorderLabel = "Hello-World" p.BorderFg = termui.ColorCyan lc1 := termui.NewLineChart() lc1.BorderLabel = "dot-mode Line Chart" lc1.Mode = "dot" lc1.Data = sinps lc1.Width = 26 lc1.Height = 12 lc1.X = 51 lc1.DotStyle = '+' lc1.AxesColor = termui.ColorWhite lc1.LineColor = termui.ColorYellow | termui.AttrBold g0 := termui.NewGauge() g0.Percent = 40 g0.Width = 50 g0.Height = 3 g0.Y = 3 g0.BorderLabel = "Slim Gauge" g0.BarColor = termui.ColorRed g0.BorderFg = termui.ColorWhite g0.BorderLabelFg = termui.ColorCyan termui.Render(p, g0, lc1) termui.Handle("/sys", func(e termui.Event) { k, ok := e.Data.(termui.EvtKbd) if ok && (k.KeyStr == "q" || k.KeyStr == "<escape>") { termui.StopLoop() } }) termui.Loop() }
func setupHandlers() { termui.Handle("/sys/kbd/C-c", func(termui.Event) { termui.StopLoop() }) termui.Handle("/sys/kbd", func(ev termui.Event) { if kbdEvent, ok := ev.Data.(termui.EvtKbd); ok { keyStr := kbdEvent.KeyStr switch { case keyStr == "<enter>": inp := parMap["input"].Text count += 1 //addToOutput(fmt.Sprintf("parsing %d", count)) parseInput(inp) parMap["input"].Text = "" //addToOutput(fmt.Sprintf("cleared %d", count)) case keyStr == "<space>": parMap["input"].Text += " " case keyStr == "C-8", keyStr == "<backspace>": // for some reason, backspace is C-8 if len(parMap["input"].Text) > 0 { parMap["input"].Text = parMap["input"].Text[:len(parMap["input"].Text)-1] } case keyStr == "<up>": for _, linesItem := range linesMap { linesItem.Up() } case keyStr == "<down>": for _, linesItem := range linesMap { linesItem.Down() } case strings.Contains(keyStr, "<"): default: parMap["input"].Text += keyStr } update() } else { dataType := reflect.TypeOf(ev.Data) addToOutput("event type of " + fmt.Sprint(dataType)) update() } }) termui.Handle("/sys/wnd/resize", func(e termui.Event) { adjustDimensions() update() }) }
func DispatchCommand(command string) { if command == "json" || command == "ejson" { EnableEJSONParsing = !EnableEJSONParsing if EnableEJSONParsing { Display <- NewConsoleMsg(COMMAND, "EJSON parsing enabled") } else { Display <- NewConsoleMsg(COMMAND, "EJSON parsing disabled") } } else if command == "exit" || command == "quit" { ui.StopLoop() } }
func sparkLinesEventLoop() { ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() ui.Body.Align() ui.Render(ui.Body) }) ui.Loop() // blocking call }
func main() { flag.Parse() if err := ui.Init(); err != nil { panic(err) } defer ui.Close() draw() ui.Handle("/sys/kbd", func(e ui.Event) { ev := e.Data.(ui.EvtKbd) switch ev.KeyStr { case ":": promptMsg = ":" case "C-8": if l := len(promptMsg); l != 0 { promptMsg = promptMsg[:l-1] } case "<enter>": handleInput() promptMsg = "" case "<left>": case "<up>": if reportPage > 0 { reportPage-- } case "<right>": case "<down>": reportPage++ case "<escape>": promptMsg = "" default: // TODO: filter irrelevant keys such as up, down, etc. promptMsg += ev.KeyStr } refresh() }) ui.Handle("/sys/kbd/C-c", func(ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(ui.Event) { loadProfile(false) loadStats() refresh() }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() refresh() }) ui.Body.Align() ui.Render(ui.Body) ui.Loop() }
func main() { // run as client if len(os.Args) > 1 { fmt.Print(debug.ConnectAndListen()) return } // run as server go func() { panic(debug.ListenAndServe()) }() if err := termui.Init(); err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") b := termui.NewBlock() b.Width = 20 b.Height = 20 b.Float = termui.AlignCenter b.BorderLabel = "[HELLO](fg-red,bg-white) [WORLD](fg-blue,bg-green)" termui.Render(b) termui.Handle("/sys", func(e termui.Event) { k, ok := e.Data.(termui.EvtKbd) debug.Logf("->%v\n", e) if ok && k.KeyStr == "q" { termui.StopLoop() } }) termui.Handle(("/usr"), func(e termui.Event) { debug.Logf("->%v\n", e) }) termui.Handle("/timer/1s", func(e termui.Event) { t := e.Data.(termui.EvtTimer) termui.SendCustomEvt("/usr/t", t.Count) if t.Count%2 == 0 { b.BorderLabel = "[HELLO](fg-red,bg-green) [WORLD](fg-blue,bg-white)" } else { b.BorderLabel = "[HELLO](fg-blue,bg-white) [WORLD](fg-red,bg-green)" } termui.Render(b) }) termui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") bc := termui.NewMBarChart() math := []int{90, 85, 90, 80} english := []int{70, 85, 75, 60} science := []int{75, 60, 80, 85} compsci := []int{100, 100, 100, 100} bc.Data[0] = math bc.Data[1] = english bc.Data[2] = science bc.Data[3] = compsci studentsName := []string{"Ken", "Rob", "Dennis", "Linus"} bc.BorderLabel = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %" bc.Width = 100 bc.Height = 30 bc.Y = 0 bc.BarWidth = 10 bc.DataLabels = studentsName bc.ShowScale = true //Show y_axis scale value (min and max) bc.SetMax(400) bc.TextColor = termui.ColorGreen //this is color for label (x-axis) bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience bc.BarColor[1] = termui.ColorYellow //Bar Color for english bc.NumColor[3] = termui.ColorRed // Num color for computerscience bc.NumColor[1] = termui.ColorRed // num color for english //Other colors are automatically populated, btw All the students seems do well in computerscience. :p termui.Render(bc) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") par0 := termui.NewPar("Borderless Text") par0.Height = 1 par0.Width = 20 par0.Y = 1 par0.Border = false par1 := termui.NewPar("你好,世界。") par1.Height = 3 par1.Width = 17 par1.X = 20 par1.BorderLabel = "标签" par2 := termui.NewPar("Simple colored text\nwith label. It [can be](fg-red) multilined with \\n or [break automatically](fg-red,fg-bold)") par2.Height = 5 par2.Width = 37 par2.Y = 4 par2.BorderLabel = "Multiline" par2.BorderFg = termui.ColorYellow par3 := termui.NewPar("Long text with label and it is auto trimmed.") par3.Height = 3 par3.Width = 37 par3.Y = 9 par3.BorderLabel = "Auto Trim" termui.Render(par0, par1, par2, par3) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func (ui *tatui) initHandles() { // Setup handlers termui.Handle("/timer/1s", func(e termui.Event) { t := e.Data.(termui.EvtTimer) ui.draw(int(t.Count)) }) termui.Handle("/sys/kbd/C-q", func(termui.Event) { termui.StopLoop() }) // Show Home -> C-h, but send <backspace> event termui.Handle("/sys/kbd/<backspace>", func(e termui.Event) { ui.showHome() }) // C-c is same as /clear termui.Handle("/sys/kbd/C-c", func(e termui.Event) { ui.clearUI() }) // All topics termui.Handle("/sys/kbd/C-b", func(e termui.Event) { if ui.current == uiMessage { ui.showMessages() } }) // All topics termui.Handle("/sys/kbd/C-a", func(e termui.Event) { ui.current = uiTopics ui.onlyFavorites = "false" ui.onlyUnread = false ui.showTopics() }) // Unread Topics termui.Handle("/sys/kbd/C-r", func(e termui.Event) { ui.showUnreadTopics() }) // toggle usernames termui.Handle("/sys/kbd/C-u", func(e termui.Event) { ui.toggleUsernames(false) }) // Favorites Topics termui.Handle("/sys/kbd/C-f", func(e termui.Event) { ui.showFavoritesTopics() }) termui.Handle("/sys/kbd/<up>", func(e termui.Event) { ui.move("up") }) termui.Handle("/sys/kbd/<down>", func(e termui.Event) { ui.move("down") }) termui.Handle("/sys/kbd/<enter>", func(e termui.Event) { switch ui.selectedPane { case uiTopics: ui.enterTopic() return case uiMessages: ui.enterMessage() return case uiActionBox: ui.processMsg() ui.render() } }) termui.Handle("/sys/kbd/<space>", func(e termui.Event) { if ui.isOnActionBox() { ui.send.Text += " " } ui.render() }) termui.Handle("/sys/kbd/<tab>", func(e termui.Event) { if ui.isOnActionBox() && len(ui.send.Text) > 0 && !strings.HasSuffix(ui.send.Text, " ") { ui.autocomplete() } else { ui.switchBox() } }) termui.Handle("/sys/kbd/C-8", func(e termui.Event) { if !ui.isOnActionBox() { return } if len(ui.send.Text) > 0 { ui.send.Text = ui.send.Text[:len(ui.send.Text)-1] ui.render() } }) termui.Handle("/sys/kbd/C-k", func(e termui.Event) { if ui.currentModeOnTopic[ui.currentTopic.Topic] == "/run" { ui.runActionOnMessage(true) } else if ui.currentModeOnTopic[ui.currentTopic.Topic] == "/monitoring" { ui.monitoringActionOnMessage() } }) termui.Handle("/sys/kbd/C-j", func(e termui.Event) { if ui.currentModeOnTopic[ui.currentTopic.Topic] == "/run" { ui.runActionOnMessage(false) } else if ui.currentModeOnTopic[ui.currentTopic.Topic] == "/monitoring" { ui.monitoringActionOnMessage() } }) termui.Handle("/sys/kbd/C-p", func(e termui.Event) { if _, ok := ui.uilists[uiMessages][ui.selectedPaneMessages]; ok { ui.openLinksInBrowser() } }) termui.Handle("/sys/kbd/C-t", func(e termui.Event) { ui.toggleTopMenu(false) }) termui.Handle("/sys/kbd/C-y", func(e termui.Event) { ui.toggleActionBox(false) }) termui.Handle("/sys/kbd/C-o", func(e termui.Event) { if _, ok := ui.uilists[uiMessages][ui.selectedPaneMessages]; ok { ui.openInTatwebui() } }) termui.Handle("/sys/kbd", func(e termui.Event) { if !ui.isOnActionBox() { ui.switchToActionBox() } ui.send.BorderFg = termui.ColorRed if _, ok := ui.uilists[uiActionBox][0]; ok { ui.uilists[uiActionBox][0].list.BorderFg = termui.ColorWhite } char := e.Data.(termui.EvtKbd).KeyStr ui.send.Text += char ui.render() }) for _, h := range ui.hooks { if h.Shortcut == "" { continue } if _, ok := termui.DefaultEvtStream.Handlers["/sys/kbd/"+h.Shortcut]; ok { internal.Exit("Shortcut %s is already used in tatcli", h.Shortcut) } termui.Handle("/sys/kbd/"+h.Shortcut, func(e termui.Event) { ui.RunExec(nil, e.Path, "") }) } }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() //termui.UseTheme("helloworld") g0 := termui.NewGauge() g0.Percent = 40 g0.Width = 50 g0.Height = 3 g0.BorderLabel = "Slim Gauge" g0.BarColor = termui.ColorRed g0.BorderFg = termui.ColorWhite g0.BorderLabelFg = termui.ColorCyan gg := termui.NewBlock() gg.Width = 50 gg.Height = 5 gg.Y = 12 gg.BorderLabel = "TEST" gg.Align() g2 := termui.NewGauge() g2.Percent = 60 g2.Width = 50 g2.Height = 3 g2.PercentColor = termui.ColorBlue g2.Y = 3 g2.BorderLabel = "Slim Gauge" g2.BarColor = termui.ColorYellow g2.BorderFg = termui.ColorWhite g1 := termui.NewGauge() g1.Percent = 30 g1.Width = 50 g1.Height = 5 g1.Y = 6 g1.BorderLabel = "Big Gauge" g1.PercentColor = termui.ColorYellow g1.BarColor = termui.ColorGreen g1.BorderFg = termui.ColorWhite g1.BorderLabelFg = termui.ColorMagenta g3 := termui.NewGauge() g3.Percent = 50 g3.Width = 50 g3.Height = 3 g3.Y = 11 g3.BorderLabel = "Gauge with custom label" g3.Label = "{{percent}}% (100MBs free)" g3.LabelAlign = termui.AlignRight g4 := termui.NewGauge() g4.Percent = 50 g4.Width = 50 g4.Height = 3 g4.Y = 14 g4.BorderLabel = "Gauge" g4.Label = "Gauge with custom highlighted label" g4.PercentColor = termui.ColorYellow g4.BarColor = termui.ColorGreen g4.PercentColorHighlighted = termui.ColorBlack termui.Render(g0, g1, g2, g3, g4) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func main() { //set log file logFileName := "btc.log" logFile, logErr := os.OpenFile(logFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) if logErr != nil { fmt.Println("Fail to find", *logFile, "cServer start Failed") return } log.SetOutput(logFile) log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Printf("cpu num %d", runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU()) if err := ui.Init(); err != nil { log.Printf("ui init err : %s", err) return } defer ui.Close() par = ui.NewPar("Last Price") par.Height = 3 par.TextFgColor = ui.ColorWhite par.BorderLabel = "Last Price" infoPar = ui.NewPar("Price Info") infoPar.Height = 3 infoPar.TextFgColor = ui.ColorWhite infoPar.BorderLabel = "Price Info" currentTime := time.Now().Format("2006-01-02 15:04:05") timePar := ui.NewPar(currentTime) timePar.Height = 3 timePar.TextFgColor = ui.ColorYellow timePar.BorderLabel = "Current Time" strItems := []string{} delegateList = ui.NewList() delegateList.Items = strItems delegateList.ItemFgColor = ui.ColorYellow delegateList.BorderLabel = "Delegate List" delegateList.Height = 23 dealList = ui.NewList() dealList.Items = strItems dealList.ItemFgColor = ui.ColorYellow dealList.Height = 23 dealList.BorderLabel = "Deal List" ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, par), ui.NewCol(6, 0, timePar))) ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, infoPar))) ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, delegateList), ui.NewCol(6, 0, dealList))) ui.Body.Align() ui.Render(ui.Body) // websocket connect log.Printf("connecting to %s", url) c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // message done chan done := make(chan struct{}) exit := func() { err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Printf("write close: %s", err) } else { select { case <-done: case <-time.After(time.Second): } c.Close() } ui.StopLoop() } ui.Handle("/sys/kbd/q", func(ui.Event) { exit() }) ui.Handle("/sys/kbd/p", func(ui.Event) { if !uiPaused { uiPaused = true } else { uiPaused = false } }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() ui.Body.Align() ui.Render(ui.Body) }) ui.Handle("/timer/1s", func(e ui.Event) { currentTime := time.Now().Format("2006-01-02 15:04:05") timePar.Text = currentTime }) go func() { for { //or use message if !uiPaused { time.Sleep(time.Millisecond * 50) ui.Render(ui.Body) } else { time.Sleep(time.Millisecond * 200) } } }() //----------------------- stocket message -------------- msgChan := make(chan []byte) //获取消息 go func() { defer c.Close() defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Printf("read err: %s", err) return } msgChan <- message } }() //订阅消息 sendSubChannel(c) //heart check via pingChan go func() { defer close(pingChan) for { if c.WriteMessage(websocket.TextMessage, []byte("{\"event\": \"ping\"}")); err != nil { log.Printf("send ping message err: %s", err) break } log.Println("send ping message") select { case <-pingChan: log.Println("server is alive") //收到数据 1s 后继续发送心跳 time.Sleep(time.Second) case <-time.After(time.Second * 1): //超时 重新连接 socket reConnectTimes := 0 for { if reConnectTimes > 5 { log.Fatal("websocket connect failed") break } _c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { log.Println("re-connect websocket faild dial:", err) log.Println("after 3s retry connect websocket") reConnectTimes++ time.Sleep(time.Second * 3) } else { log.Println("re-connect websocket success") c = _c sendSubChannel(c) break } } } } }() //开启10个worker 处理消息 for i := 0; i < 10; i++ { go processMessage(msgChan) } //开始阻塞 循环terminal ui ui.Loop() }
func parseInput(inp string) { inp = strings.ToLower(inp) switch state { case 0: // getting host if inp == "" { inp = "www.marktai.com/T9" } host = inp changeState(6) case 6: if inp == "" { inp = "j" } switch inp { case "j", "join": _, err := GetAllGames(host) if err != nil { addToOutput(fmt.Sprintf("%#v", err)) if strings.Contains(err.Error(), "no such host") { changeState(0) } } else { changeState(1) } case "c", "create": changeState(7) } case 1: // getting game id var err error if gameid, err = stringtoUint(inp); err != nil { addToOutput("Bad Game ID") } else { changeState(2) } case 2: // getting player id if inp == "" { inp = "0" } var err error if playerid, err = stringtoUint(inp); err != nil { addToOutput("Bad Player ID") } else { if err := refreshBoard(host, gameid, playerid); err != nil { } else { changeState(3) clearOutput() displayInfo(globalGame) addToOutput(helpText) go Ws(host, gameid) } } case 3: // getting generic command switch inp { case "m", "move": if globalGame.Players[globalGame.Turn/10] == playerid { if tempBox := globalGame.Turn % 10; tempBox == 9 { changeState(4) } else { box = tempBox changeState(5) } } else { addToOutput("Not your turn") } case "i", "info": // display info displayInfo(globalGame) case "r", "refresh": refreshBoard(host, gameid, playerid) addToOutput("Refreshed") case "p", "player": // switch players changeState(2) case "s", "switch": // switch game changeState(1) case "c", "clear": // switch game clearOutput() case "q", "quit", ":q": termui.StopLoop() case "h", "help": addToOutput(helpText) } case 4, 5: // getting box or square goodInput := false var err error var tempNum uint if inp == "b" || inp == "back" { changeState(3) } else { // if number input like 1 if tempNum, err = stringtoUint(inp); err == nil { goodInput = true } else { var ok bool // if word input like top middle if tempNum, ok = stringToBox[strings.Replace(inp, " ", "", -1)]; ok { goodInput = true } else { addToOutput("Bad Position") } } } if goodInput { if state == 4 { box = tempNum changeState(5) } else if state == 5 { square = tempNum err := MakeMove(host, gameid, playerid, box, square) if err != nil { addToOutput(fmt.Sprintf("%#v", err)) } changeState(3) refreshBoard(host, gameid, playerid) } } case 7: if inp == "" { inp = "0" } var err error if players[0], err = stringtoUint(inp); err != nil { addToOutput("Bad Player ID") } else { changeState(8) } case 8: if inp == "" { inp = "1" } var err error if players[1], err = stringtoUint(inp); err != nil { addToOutput("Bad Player ID") } else { id, err := MakeGame(host, players[0], players[1]) if err != nil { changeState(6) addToOutput(fmt.Sprintf("%#v", err)) } else { changeState(3) playerid = players[0] gameid = id refreshBoard(host, id, players[0]) displayInfo(globalGame) go Ws(host, gameid) } } } }
func RenderPipeline(executionId string) { if err := ui.Init(); err != nil { panic(err) } defer ui.Close() ui.Merge("timer", ui.NewTimerCh(time.Second*5)) ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, instructions), ), ui.NewRow( ui.NewCol(12, 0, info), ), ui.NewRow( ui.NewCol(5, 0, stages), ui.NewCol(7, 0, exception), ), ) ui.Body.Align() draw := func(exe *Execution) { if exe != nil { drawInstructions() drawInfo(exe) drawStages(exe) ui.Body.Align() } ui.Render(ui.Body) } fetchAndDraw := func() { execution, _ = client.GetExecutionById(executionId) if orcaDetails == nil { debug.Log("fetching orca details\n") searchResults, _ := client.InstanceSearch(execution.ExecutingInstance) if len(searchResults) > 0 && len(searchResults[0].Results) > 0 { result := searchResults[0].Results[0] orcaDetails, _ = client.GetInstanceDetails(result) } } autoscalingUrls := execution.getScalingActivitiesUrls() ch := make(chan []AutoScalingActivity, len(autoscalingUrls)) client.GetAutoScalingActivity(autoscalingUrls, ch) activity := <-ch autoScalingActivities = append(autoScalingActivities, (activity)...) draw(execution) } fetchAndDraw() ui.Handle("/timer/5s", func(e ui.Event) { fetchAndDraw() }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() ui.Body.Align() ui.Render(ui.Body) }) ui.Handle("/sys/kbd/f", func(e ui.Event) { showSucceeded = !showSucceeded fetchAndDraw() }) ui.Handle("/sys/kbd/q", func(e ui.Event) { ui.StopLoop() }) ui.Handle("/sys/kbd/l", func(e ui.Event) { if orcaDetails != nil { tomcatLogUrl := fmt.Sprintf("http://%s:7001/AdminLogs/list?view=tomcat/catalina.out", orcaDetails.PrivateIpAddress) debug.Log(orcaDetails.PrivateIpAddress) cmd := exec.Command("open", tomcatLogUrl) go cmd.Start() } }) ui.Handle("/sys/kbd/s", func(e ui.Event) { sourceUrl := fmt.Sprintf("http://spinnaker-api.prod.netflix.net/pipelines/%s", executionId) cmd := exec.Command("open", sourceUrl) go cmd.Start() }) ui.Handle("/sys/kbd/p", func(e ui.Event) { pipelineUrl := fmt.Sprintf("http://spinnaker.prod.netflix.net/#/applications/%s/executions/%s", execution.Application, execution.Id) cmd := exec.Command("open", pipelineUrl) go cmd.Start() }) ui.Handle("/sys/kbd/c", func(e ui.Event) { pipelineUrl := fmt.Sprintf("http://spinnaker.prod.netflix.net/#/applications/%s/executions/configure/%s", execution.Application, execution.PipelineConfigId) cmd := exec.Command("open", pipelineUrl) go cmd.Start() }) ui.Loop() }
func main() { configFile := flag.String("config", "config.json", "Configuration file") flag.Parse() monitors := readConfig(*configFile) updates := make(chan monitor.CheckUpdate) logbuf := new(bytes.Buffer) log.SetOutput(logbuf) err := termui.Init() if err != nil { log.Fatalf("Unable to init termui: %v\n", err) } defer termui.Close() list := termui.NewList() var urls []string for _, m := range monitors { e := fmt.Sprintf("[%v] %v", m.index, m.monitor.Source()) urls = append(urls, e) if list.Width < int(float64(len(e))*float64(1.5)) { list.Width = int(float64(len(e)) * float64(1.5)) } } list.Items = urls list.ItemFgColor = termui.ColorYellow list.BorderLabel = "URLs" list.Height = 8 list.Y = 0 list.X = 0 sp := termui.NewSparklines() sp.BorderLabel = "Response times" sp.Y = list.Height sp.X = 0 sp.Height = list.Height for i, _ := range urls { spark := termui.Sparkline{} spark.Height = 1 spark.Title = fmt.Sprintf("URL %v", i) spark.LineColor = termui.ColorCyan spark.TitleColor = termui.ColorYellow sp.Add(spark) } logPar := termui.NewPar(logbuf.String()) logPar.Height = 20 termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, list), termui.NewCol(6, 0, sp)), termui.NewRow( termui.NewCol(12, 0, logPar))) termui.Body.Align() for _, m := range monitors { go m.monitor.Check(updates, m.index) } loop: for { select { case u := <-updates: if u.Healthy && u.Err == nil { sp.Lines[u.Id].LineColor = COLOR_OK } else { sp.Lines[u.Id].LineColor = COLOR_KO } case <-time.After(2 * time.Second): break loop } } termui.Render(termui.Body) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Handle("/timer/1s", func(e termui.Event) { t := e.Data.(termui.EvtTimer) if t.Count%5 == 0 { for _, m := range monitors { go m.monitor.Check(updates, m.index) } loop: for { select { case u := <-updates: sp.Lines[u.Id].Data = append(sp.Lines[u.Id].Data, int(u.Duration)) if u.Healthy && u.Err == nil { sp.Lines[u.Id].LineColor = COLOR_OK } else { sp.Lines[u.Id].LineColor = COLOR_KO } case <-time.After(2 * time.Second): break loop } } logPar.Text = logbuf.String() termui.Render(termui.Body) } }) termui.Loop() }
// monitor starts a terminal UI based monitoring tool for the requested metrics. func monitor(ctx *cli.Context) error { var ( client rpc.Client err error ) // Attach to an Expanse node over IPC or RPC endpoint := ctx.String(monitorCommandAttachFlag.Name) if client, err = utils.NewRemoteRPCClientFromString(endpoint); err != nil { utils.Fatalf("Unable to attach to gexp node: %v", err) } defer client.Close() // Retrieve all the available metrics and resolve the user pattens metrics, err := retrieveMetrics(client) if err != nil { utils.Fatalf("Failed to retrieve system metrics: %v", err) } monitored := resolveMetrics(metrics, ctx.Args()) if len(monitored) == 0 { list := expandMetrics(metrics, "") sort.Strings(list) if len(list) > 0 { utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) } else { utils.Fatalf("No metrics collected by gexp (--%s).\n", utils.MetricsEnabledFlag.Name) } } sort.Strings(monitored) if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 { utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - ")) } // Create and configure the chart UI defaults if err := termui.Init(); err != nil { utils.Fatalf("Unable to initialize terminal UI: %v", err) } defer termui.Close() rows := len(monitored) if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max { rows = max } cols := (len(monitored) + rows - 1) / rows for i := 0; i < rows; i++ { termui.Body.AddRows(termui.NewRow()) } // Create each individual data chart footer := termui.NewPar("") footer.Block.Border = true footer.Height = 3 charts := make([]*termui.LineChart, len(monitored)) units := make([]int, len(monitored)) data := make([][]float64, len(monitored)) for i := 0; i < len(monitored); i++ { charts[i] = createChart((termui.TermHeight() - footer.Height) / rows) row := termui.Body.Rows[i%rows] row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i])) } termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) refreshCharts(client, monitored, data, units, charts, ctx, footer) termui.Body.Align() termui.Render(termui.Body) // Watch for various system events, and periodically refresh the charts termui.Handle("/sys/kbd/C-c", func(termui.Event) { termui.StopLoop() }) termui.Handle("/sys/wnd/resize", func(termui.Event) { termui.Body.Width = termui.TermWidth() for _, chart := range charts { chart.Height = (termui.TermHeight() - footer.Height) / rows } termui.Body.Align() termui.Render(termui.Body) }) go func() { tick := time.NewTicker(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second) for range tick.C { if refreshCharts(client, monitored, data, units, charts, ctx, footer) { termui.Body.Align() } termui.Render(termui.Body) } }() termui.Loop() return nil }
func main() { if err := ui.Init(); err != nil { panic(err) } defer ui.Close() p := ui.NewPar(":PRESS q TO QUIT DEMO") p.Height = 3 p.Width = 50 p.TextFgColor = ui.ColorWhite p.BorderLabel = "Text Box" p.BorderFg = ui.ColorCyan p.Handle("/timer/1s", func(e ui.Event) { cnt := e.Data.(ui.EvtTimer) if cnt.Count%2 == 0 { p.TextFgColor = ui.ColorRed } else { p.TextFgColor = ui.ColorWhite } }) strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"} list := ui.NewList() list.Items = strs list.ItemFgColor = ui.ColorYellow list.BorderLabel = "List" list.Height = 7 list.Width = 25 list.Y = 4 g := ui.NewGauge() g.Percent = 50 g.Width = 50 g.Height = 3 g.Y = 11 g.BorderLabel = "Gauge" g.BarColor = ui.ColorRed g.BorderFg = ui.ColorWhite g.BorderLabelFg = ui.ColorCyan spark := ui.Sparkline{} spark.Height = 1 spark.Title = "srv 0:" spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} spark.Data = spdata spark.LineColor = ui.ColorCyan spark.TitleColor = ui.ColorWhite spark1 := ui.Sparkline{} spark1.Height = 1 spark1.Title = "srv 1:" spark1.Data = spdata spark1.TitleColor = ui.ColorWhite spark1.LineColor = ui.ColorRed sp := ui.NewSparklines(spark, spark1) sp.Width = 25 sp.Height = 7 sp.BorderLabel = "Sparkline" sp.Y = 4 sp.X = 25 sinps := (func() []float64 { n := 220 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/5) } return ps })() lc := ui.NewLineChart() lc.BorderLabel = "dot-mode Line Chart" lc.Data = sinps lc.Width = 50 lc.Height = 11 lc.X = 0 lc.Y = 14 lc.AxesColor = ui.ColorWhite lc.LineColor = ui.ColorRed | ui.AttrBold lc.Mode = "dot" bc := ui.NewBarChart() bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6} bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} bc.BorderLabel = "Bar Chart" bc.Width = 26 bc.Height = 10 bc.X = 51 bc.Y = 0 bc.DataLabels = bclabels bc.BarColor = ui.ColorGreen bc.NumColor = ui.ColorBlack lc1 := ui.NewLineChart() lc1.BorderLabel = "braille-mode Line Chart" lc1.Data = sinps lc1.Width = 26 lc1.Height = 11 lc1.X = 51 lc1.Y = 14 lc1.AxesColor = ui.ColorWhite lc1.LineColor = ui.ColorYellow | ui.AttrBold p1 := ui.NewPar("Hey!\nI am a borderless block!") p1.Border = false p1.Width = 26 p1.Height = 2 p1.TextFgColor = ui.ColorMagenta p1.X = 52 p1.Y = 11 draw := func(t int) { g.Percent = t % 101 list.Items = strs[t%9:] sp.Lines[0].Data = spdata[:30+t%50] sp.Lines[1].Data = spdata[:35+t%50] lc.Data = sinps[t/2%220:] lc1.Data = sinps[2*t%220:] bc.Data = bcdata[t/2%10:] ui.Render(p, list, g, sp, lc, bc, lc1, p1) } ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { t := e.Data.(ui.EvtTimer) draw(int(t.Count)) }) ui.Loop() }
func main() { if err := ui.Init(); err != nil { panic(err) } defer ui.Close() sinps := (func() []float64 { n := 400 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/5) } return ps })() sinpsint := (func() []int { ps := make([]int, len(sinps)) for i, v := range sinps { ps[i] = int(100*v + 10) } return ps })() spark := ui.Sparkline{} spark.Height = 8 spdata := sinpsint spark.Data = spdata[:100] spark.LineColor = ui.ColorCyan spark.TitleColor = ui.ColorWhite sp := ui.NewSparklines(spark) sp.Height = 11 sp.BorderLabel = "Sparkline" lc := ui.NewLineChart() lc.BorderLabel = "braille-mode Line Chart" lc.Data = sinps lc.Height = 11 lc.AxesColor = ui.ColorWhite lc.LineColor = ui.ColorYellow | ui.AttrBold gs := make([]*ui.Gauge, 3) for i := range gs { gs[i] = ui.NewGauge() //gs[i].LabelAlign = ui.AlignCenter gs[i].Height = 2 gs[i].Border = false gs[i].Percent = i * 10 gs[i].PaddingBottom = 1 gs[i].BarColor = ui.ColorRed } ls := ui.NewList() ls.Border = false ls.Items = []string{ "[1] Downloading File 1", "", // == \newline "[2] Downloading File 2", "", "[3] Uploading File 3", } ls.Height = 5 par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget") par.Height = 5 par.BorderLabel = "Demonstration" // build layout ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, sp), ui.NewCol(6, 0, lc)), ui.NewRow( ui.NewCol(3, 0, ls), ui.NewCol(3, 0, gs[0], gs[1], gs[2]), ui.NewCol(6, 0, par))) // calculate layout ui.Body.Align() ui.Render(ui.Body) ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { t := e.Data.(ui.EvtTimer) i := t.Count if i > 103 { ui.StopLoop() return } for _, g := range gs { g.Percent = (g.Percent + 3) % 100 } sp.Lines[0].Data = spdata[:100+i] lc.Data = sinps[2*i:] ui.Render(ui.Body) }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() ui.Body.Align() ui.Render(ui.Body) }) ui.Loop() }
func (d *Dash) Start() { go d.run() go mock() PL := MAX_WIDTH / d.width err := termui.Init() if err != nil { panic(err) } defer termui.Close() var lists []termui.Bufferer draw := func() { newRow := false row := 0 if d.dashboard { row = 1 // row=0 :view } d.lock.Lock() var hosts []string if len(d.hosts) == 0 { hosts = d.sortHost() } else { hosts = d.hosts } index := 0 for _, h := range hosts { for s := range d.stat[h] { st, ok := d.stat[h][s] if !ok { continue } ls := termui.NewList() ls.Items = st.List() ls.ItemFgColor = termui.ColorYellow ls.BorderLabel = fmt.Sprintf("%s@%s", s, h) ls.Height = d.height ls.Width = d.width ls.X = (index % PL) * d.width if index >= PL && index%PL == 0 { newRow = true } if newRow { row++ } ls.Y = d.height * row newRow = false d.gList = append(d.gList, ls) index++ if index%d.page == 0 && index != 1 { index = 0 row = 0 newRow = false } } } d.lock.Unlock() if len(d.gList) > d.page { lists = d.gList[:d.page] } else { lists = d.gList[:] } } termui.Render(lists...) termui.Handle("/timer/1s", func(e termui.Event) { if len(lists) == 0 { draw() } if d.dashboard { d.drawView() termui.Render(d.view) } else { for index := range lists { ls := lists[index].(*termui.List) dd := strings.Split(ls.BorderLabel, "@") sv, pc := dd[0], dd[1] d.lock.RLock() ls.Items = d.stat[pc][sv].List() d.lock.RUnlock() lists[index] = ls } termui.Render(lists...) } }) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Handle("/sys/kbd/p", func(termui.Event) { termui.Clear() start := (d.curPage - 1) * d.page if start < 0 { start = 0 } else { d.curPage-- } lists = d.gList[start : start+d.page] d.lock.Lock() for index := range lists { ls := lists[index].(*termui.List) dd := strings.Split(ls.BorderLabel, "@") sv, pc := dd[0], dd[1] ls.Items = d.stat[sv][pc].List() lists[index] = ls } d.lock.Unlock() termui.Render(lists...) }) termui.Handle("/sys/kbd/n", func(termui.Event) { termui.Clear() end := (d.curPage + 1) * d.page if end > len(d.gList) { end = len(d.gList) - 1 } else { d.curPage++ } lists = d.gList[end-d.page : end] d.lock.Lock() for index := range lists { ls := lists[index].(*termui.List) dd := strings.Split(ls.BorderLabel, "@") sv, pc := dd[0], dd[1] ls.Items = d.stat[sv][pc].List() lists[index] = ls } d.lock.Unlock() termui.Render(lists...) }) termui.Handle("/sys/kbd/a", func(termui.Event) { termui.Clear() d.dashboard = true }) termui.Handle("/sys/kbd/s", func(termui.Event) { termui.Clear() d.dashboard = false }) termui.Loop() }