func init() { err := termui.Init() if err != nil { panic(err) } termui.UseTheme("default") ui = NewUi() refreshTicker := time.NewTicker(time.Millisecond * 50) evt := termui.EventCh() ui.refresh() go func() { for { select { case e := <-evt: if e.Type == termui.EventKey && e.Ch == 'q' { os.Exit(1) } if e.Type == termui.EventResize { ui.gridWidth = termui.TermWidth() ui.refresh() } case <-refreshTicker.C: ui.refresh() } } }() }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() w11 := ui.NewPar("Hello world") w11.Height = 10 w11.Border.Label = "Hello" w11.Border.LabelFgColor = ui.ColorGreen w12 := ui.NewPar("first") w12.Height = 20 w2 := ui.NewPar("second") w2.Height = 20 ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, w11), ui.NewCol(6, 0, w12)), ui.NewRow( ui.NewCol(12, 0, w2))) ui.Body.Align() ui.Render(ui.Body) <-ui.EventCh() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() termui.UseTheme("helloworld") strs := []string{ "[0] github.com/gizak/termui", "[1] 你好,世界", "[2] こんにちは世界", "[3] keyboard.go", "[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.Border.Label = "List" ls.Height = 7 ls.Width = 25 ls.Y = 0 termui.Render(ls) <-termui.EventCh() }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() termui.UseTheme("helloworld") 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.Border.Label = "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.EventCh() }
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.HasBorder = 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.Border.Label = "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.Border.FgColor = termui.ColorCyan spls2.X = 21 spls2.Border.Label = "Tweeked Sparkline" termui.Render(spls0, spls1, spls2) <-termui.EventCh() }
func readMessage(message *imap.MessageInfo) { set := new(imap.SeqSet) set.AddNum(message.Seq) cmd, err := imap.Wait(c.Fetch(set, BODY_PART_NAME)) panicMaybe(err) reader, err := messageReader(cmd.Data[0].MessageInfo()) panicMaybe(err) scanner := bufio.NewScanner(reader) var lines []string for scanner.Scan() { lines = append(lines, scanner.Text()) } messageBodyStr := strings.Join(lines[:min(len(lines), ui.TermHeight()-2)], "\n") if len(messageBodyStr) <= 0 { LOG.Printf("Message body was empty or could not be retrieved: +%v\n", err) return } msgBox := ui.NewPar(messageBodyStr) msgBox.Border.Label = "Reading Message" msgBox.Height = ui.TermHeight() msgBox.Width = ui.TermWidth() msgBox.Y = 0 ui.Render(msgBox) topLineIndex := 0 redraw := make(chan bool) for { select { case e := <-ui.EventCh(): switch e.Key { case ui.KeyArrowDown: topLineIndex = max(0, min( len(lines)-msgBox.Height/2, topLineIndex+1)) go func() { redraw <- true }() case ui.KeyArrowUp: topLineIndex = max(0, topLineIndex-1) go func() { redraw <- true }() case ui.KeyEsc: // back to "list messages" return } case <-redraw: messageBodyStr = strings.Join(lines[topLineIndex+1:], "\n") msgBox.Text = messageBodyStr ui.Render(msgBox) } } }
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.Border.Label = "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.Border.Label = "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.Border.Label = "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.EventCh() }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() initial() ech := ui.EventCh() for screen := intro; screen != nil; { screen = screen(ech) } }
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.Border.Label = "Slim Gauge" g0.BarColor = termui.ColorRed g0.Border.FgColor = termui.ColorWhite g0.Border.LabelFgColor = termui.ColorCyan g2 := termui.NewGauge() g2.Percent = 60 g2.Width = 50 g2.Height = 3 g2.PercentColor = termui.ColorBlue g2.Y = 3 g2.Border.Label = "Slim Gauge" g2.BarColor = termui.ColorYellow g2.Border.FgColor = termui.ColorWhite g1 := termui.NewGauge() g1.Percent = 30 g1.Width = 50 g1.Height = 5 g1.Y = 6 g1.Border.Label = "Big Gauge" g1.PercentColor = termui.ColorYellow g1.BarColor = termui.ColorGreen g1.Border.FgColor = termui.ColorWhite g1.Border.LabelFgColor = termui.ColorMagenta g3 := termui.NewGauge() g3.Percent = 50 g3.Width = 50 g3.Height = 3 g3.Y = 11 g3.Border.Label = "Gauge with custom label" g3.Label = "{{percent}}% (100MBs free)" g3.LabelAlign = termui.AlignRight termui.Render(g0, g1, g2, g3) <-termui.EventCh() }
func showSubreddit(subredditName string) error { r := geddit.NewSession("r by /u/bnadland") submissions, err := r.SubredditSubmissions(subredditName, geddit.HotSubmissions, geddit.ListingOptions{}) if err != nil { return err } isActive := true cursor := 3 for isActive { entries := []string{} for i, submission := range submissions { entries = append(entries, fmt.Sprintf("%s %s", isActiveCursor(cursor, i), submission.Title)) } ls := termui.NewList() ls.Items = entries ls.ItemFgColor = termui.ColorDefault ls.Border.Label = fmt.Sprintf("Subreddit: %s", subredditName) ls.Height = termui.TermHeight() ls.Width = termui.TermWidth() ls.Y = 0 termui.Render(ls) event := <-termui.EventCh() if event.Type == termui.EventKey { switch event.Key { case termui.KeyArrowLeft: isActive = false case termui.KeyArrowDown: cursor = cursor + 1 if cursor > len(submissions) { cursor = len(submissions) } case termui.KeyArrowUp: cursor = cursor - 1 if cursor < 0 { cursor = 0 } } } } return nil }
func main() { err := ui.Init() fmt.Println(daemon.UpSince()) if err != nil { fmt.Println("Could not initialise UI") } defer ui.Close() ut, _ := daemon.Uptime() p := ui.NewPar(ut.String()) p.Height = 3 p.Width = 50 p.TextFgColor = ui.ColorWhite p.Border.Label = "Uptime" p.Border.FgColor = ui.ColorCyan g0 := ui.NewGauge() g0.Percent = 40 g0.Width = 50 g0.Height = 3 g0.Border.Label = "Memory" g0.BarColor = ui.ColorRed g0.Border.FgColor = ui.ColorWhite g0.Border.LabelFgColor = ui.ColorCyan g2 := ui.NewGauge() g2.Percent = 60 g2.Width = 50 g2.Height = 3 g2.PercentColor = ui.ColorBlue g2.Y = 3 g2.Border.Label = "CPU" g2.BarColor = ui.ColorYellow g2.Border.FgColor = ui.ColorWhite ui.Body.AddRows(ui.NewRow(ui.NewCol(6, 0, g0), ui.NewCol(6, 0, p)), ui.NewRow(ui.NewCol(6, 0, g2))) ui.Body.Align() ui.Render(ui.Body) go updateMemCPU(g2, g0) go updateUptime(p) <-ui.EventCh() }
func maintainSparkLines(redraw chan bool, quit chan bool) { evt := ui.EventCh() for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { quit <- true return } if e.Type == ui.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() go func() { redraw <- true }() } case <-redraw: ui.Render(ui.Body) } } }
func main() { // show flashscreen views.MainView().Init() err := termui.Init() if err != nil { panic(err) } defer termui.Close() currentView = views.MainView().SwitchToView() go func() { for { currentView.Render() time.Sleep(1 * time.Second) } }() for { e := <-termui.EventCh() if e.Type == termui.EventKey { if e.Key == termui.KeyEsc { break } else if e.Key == termui.KeyArrowLeft { currentView = views.EventView().SwitchToView() currentView.Render() } else if e.Key == termui.KeyArrowRight { currentView = views.MainView().SwitchToView() currentView.Render() } else if e.Key == termui.KeyArrowUp { currentView = views.RPSView().SwitchToView() currentView.Render() } else { // FIXME: quit with any key break } } } }
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.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %" bc.Width = 100 bc.Height = 50 bc.Y = 10 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.EventCh() }
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.HasBorder = false par1 := termui.NewPar("你好,世界。") par1.Height = 3 par1.Width = 17 par1.X = 20 par1.Border.Label = "标签" par2 := termui.NewPar("Simple colored text\nwith label. It [can be](RED) multilined with \\n or [break automatically](GREEN, BOLD)") par2.RendererFactory = termui.MarkdownTextRendererFactory{} par2.Height = 5 par2.Width = 37 par2.Y = 4 par2.Border.Label = "Multiline" par2.Border.FgColor = termui.ColorYellow par3 := termui.NewPar("Long text with label and it is auto trimmed.") par3.Height = 3 par3.Width = 37 par3.Y = 9 par3.Border.Label = "Auto Trim" termui.Render(par0, par1, par2, par3) <-termui.EventCh() }
func showMainWindow() { err := ui.Init() if 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.Border.Label = "Text Box" p.Border.FgColor = ui.ColorCyan draw := func(t int) { ui.Render(p) } evt := ui.EventCh() i := 0 for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } default: draw(i) i++ if i == 102 { return } time.Sleep(time.Second / 2) } } }
func main() { sysmon = gtop.NewSysmon() go sysmon.MonCPU() err := termui.Init() if err != nil { panic(err) } defer termui.Close() bufferer := []termui.Bufferer{} lcpu_c, _, err := sysmon.CPUCount() if err == nil { cpu_bars = []*gtop.Bar{} bar_offset := 0 for i := 0; i < lcpu_c; i++ { b := gtop.NewBar(35, 2, 1+bar_offset, strconv.Itoa(i+1), &bufferer) cpu_bars = append(cpu_bars, b) bar_offset += b.Height } } go render_loop(bufferer) go update_cpu_bars() evt := termui.EventCh() for { select { case e := <-evt: if e.Type == termui.EventKey && e.Ch == 0 { return } } } }
func main() { flag.Usage = Usage flag.Parse() // Process ports/urls ports, _ := ParsePorts(*urls) if *self { port, err := StartSelfMonitor() if err == nil { ports = append(ports, port) } } if len(ports) == 0 { fmt.Fprintln(os.Stderr, "no ports specified. Use -ports arg to specify ports of Go apps to monitor") Usage() os.Exit(1) } if *interval <= 0 { fmt.Fprintln(os.Stderr, "update interval is not valid. Valid examples: 5s, 1m, 1h30m") Usage() os.Exit(1) } // Process vars vars, err := ParseVars(*varsArg) if err != nil { log.Fatal(err) } // Init UIData data := NewUIData(vars) for _, port := range ports { service := NewService(port, vars) data.Services = append(data.Services, service) } // Start proper UI var ui UI if len(data.Services) > 1 { ui = &TermUI{} } else { ui = &TermUISingle{} } if *dummy { ui = &DummyUI{} } if err := ui.Init(*data); err != nil { log.Fatal(err) } defer ui.Close() tick := time.NewTicker(*interval) evtCh := termui.EventCh() UpdateAll(ui, data) for { select { case <-tick.C: UpdateAll(ui, data) case e := <-evtCh: if e.Type == termui.EventKey && e.Ch == 'q' { return } if e.Type == termui.EventResize { ui.Update(*data) } } } }
// monitor starts a terminal UI based monitoring tool for the requested metrics. func monitor(ctx *cli.Context) { var ( client comms.EthereumClient err error ) // Attach to an Ethereum node over IPC or RPC endpoint := ctx.String(monitorCommandAttachFlag.Name) if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil { utils.Fatalf("Unable to attach to geth node: %v", err) } defer client.Close() xeth := rpc.NewXeth(client) // Retrieve all the available metrics and resolve the user pattens metrics, err := retrieveMetrics(xeth) 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 geth (--%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() termui.UseTheme("helloworld") 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.HasBorder = 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(xeth, monitored, data, units, charts, ctx, footer) termui.Body.Align() termui.Render(termui.Body) // Watch for various system events, and periodically refresh the charts refresh := time.Tick(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second) for { select { case event := <-termui.EventCh(): if event.Type == termui.EventKey && event.Key == termui.KeyCtrlC { return } if event.Type == termui.EventResize { termui.Body.Width = termui.TermWidth() for _, chart := range charts { chart.Height = (termui.TermHeight() - footer.Height) / rows } termui.Body.Align() termui.Render(termui.Body) } case <-refresh: if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) { termui.Body.Align() } termui.Render(termui.Body) } } }
func main() { err := ui.Init() if 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 })() // ui.UseTheme("helloworld") 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.Border.Label = "Sparkline" lc := ui.NewLineChart() lc.Border.Label = "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].Height = 2 gs[i].HasBorder = false gs[i].Percent = i * 10 gs[i].PaddingBottom = 1 gs[i].BarColor = ui.ColorRed } ls := ui.NewList() ls.HasBorder = 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.Border.Label = "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() done := make(chan bool) redraw := make(chan bool) /* update := func() { for i := 0; i < 103; i++ { for _, g := range gs { g.Percent = (g.Percent + 3) % 100 } sp.Lines[0].Data = spdata[:100+i] lc.Data = sinps[2*i:] time.Sleep(time.Second / 2) redraw <- true } done <- true } */ evt := ui.EventCh() ui.Render(ui.Body) // go update() for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } if e.Type == ui.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() go func() { redraw <- true }() } case <-done: return case <-redraw: ui.Render(ui.Body) } } }
func main() { if runtime.GOOS != "linux" { panic("Currently works only on Linux") } err := termui.Init() if err != nil { panic(err) } defer termui.Close() termWidth := 70 termui.UseTheme("helloworld") header := termui.NewPar("Press q to quit, Press j or k to switch tabs") header.Height = 1 header.Width = 50 header.HasBorder = false header.TextBgColor = termui.ColorBlue tabCpu := extra.NewTab("CPU") tabMem := extra.NewTab("MEM") tabpane := extra.NewTabpane() tabpane.Y = 1 tabpane.Width = 30 tabpane.HasBorder = false cs, errcs := getCpusStatsMap() cpusStats := NewCpusStats(cs) if errcs != nil { panic("error") } cpuTabElems := NewCpuTabElems(termWidth) Y := 0 cpuKeys := make([]string, 0, len(cs)) for key := range cs { cpuKeys = append(cpuKeys, key) } sort.Strings(cpuKeys) for _, key := range cpuKeys { g := cpuTabElems.AddGauge(key, Y, termWidth) Y += 3 tabCpu.AddBlocks(g) } cpuTabElems.LChart.Y = Y tabCpu.AddBlocks(cpuTabElems.LChart) memTabElems := NewMemTabElems(termWidth) ms, errm := getMemStats() if errm != nil { panic(errm) } memTabElems.Update(ms) tabMem.AddBlocks(memTabElems.Gauge) tabMem.AddBlocks(memTabElems.SLines) tabpane.SetTabs(*tabCpu, *tabMem) termui.Render(header, tabpane) evt := termui.EventCh() for { select { case e := <-evt: if e.Type == termui.EventKey { switch e.Ch { case 'q': return case 'j': tabpane.SetActiveLeft() termui.Render(header, tabpane) case 'k': tabpane.SetActiveRight() termui.Render(header, tabpane) } } case <-time.After(time.Second): cs, errcs := getCpusStatsMap() if errcs != nil { panic(errcs) } cpusStats.tick(cs) cpuTabElems.Update(*cpusStats) ms, errm := getMemStats() if errm != nil { panic(errm) } memTabElems.Update(ms) termui.Render(header, tabpane) } } }
func main() { pfile := flag.String("f", "", "psafe3 file") flag.Parse() fmt.Printf("Password: "******"Last Saved: %s\nLast Saved By %s @ %s", safe.Headers.LastSave.Format("2006-01-02 15:04:05"), safe.Headers.User, safe.Headers.Host)) rightpar.Height = 2 rightpar.HasBorder = false leftpar := termui.NewPar(fmt.Sprintf("File Name: %s\nLast Program: %s", filepath.Base(*pfile), safe.Headers.ProgramSave)) leftpar.Height = 2 leftpar.HasBorder = false recordlist := termui.NewList() recordlist.Height = termui.TermHeight() - 5 recordlist.Items = getRecordList(safe) recordlist.Border.Label = fmt.Sprintf("Records (%d)", len(safe.Records)) recorddetail := termui.NewPar("") recorddetail.Height = recordlist.Height recorddetail.Border.Label = "Record Information" inputbox := termui.NewPar("") inputbox.Height = 3 inputbox.Border.Label = "Input Box ([Enter] to save, [Esc] to cancel)" inputrow := termui.NewRow(termui.NewCol(12, 0, inputbox)) commandinfo := termui.NewPar(strings.Join([]string{ "Select record by typing the index number. Edit field by typing field marker.", }, "\n")) commandinfo.Height = 3 commandinfo.Border.Label = "Help" commandrow := termui.NewRow(termui.NewCol(12, 0, commandinfo)) termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, leftpar), termui.NewCol(6, 0, rightpar), ), termui.NewRow( termui.NewCol(6, 0, recordlist), termui.NewCol(6, 0, recorddetail), ), commandrow, ) termui.Body.Align() termui.Render(termui.Body) evt := termui.EventCh() inputMode := false valBuffer := bytes.Buffer{} numBuffer := bytes.Buffer{} var selRecord *pwsafe.Record var selField *string var inputPrompt string var startIndex int Main: for { select { case e := <-evt: if !inputMode && e.Type == termui.EventKey { switch e.Ch { case 'q': break Main case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': numBuffer.WriteRune(e.Ch) case '#': selIndex, _ := strconv.ParseInt(numBuffer.String(), 10, 64) selRecord = &safe.Records[selIndex] selField = nil numBuffer.Reset() case 'j': startIndex++ rlist := getRecordList(safe) recordlist.Items = rlist[startIndex:] case 'k': if startIndex > 1 { startIndex-- rlist := getRecordList(safe) recordlist.Items = rlist[startIndex:] } case 'a': selIndex := len(safe.Records) safe.Records = append(safe.Records, pwsafe.Record{}) selRecord = &safe.Records[selIndex] selRecord.UUID = uuid.NewV1() selRecord.CreationTime = time.Now() selField = nil rlist := getRecordList(safe) recordlist.Items = rlist[startIndex:] recordlist.Border.Label = fmt.Sprintf("Records (%d)", len(safe.Records)) case 'g': selField = &selRecord.Group inputPrompt = "Group: " inputMode = true valBuffer.WriteString(selRecord.Group) inputbox.Text = inputPrompt + valBuffer.String() case 't': selField = &selRecord.Title inputPrompt = "Title: " inputMode = true valBuffer.WriteString(selRecord.Title) inputbox.Text = inputPrompt + valBuffer.String() case 'u': selField = &selRecord.Username inputPrompt = "Username: "******"Password: "******"Url: " inputMode = true valBuffer.WriteString(selRecord.Url) inputbox.Text = inputPrompt + valBuffer.String() case 'n': selField = &selRecord.Notes inputPrompt = "Notes: " inputMode = true valBuffer.WriteString(selRecord.Notes) inputbox.Text = inputPrompt + valBuffer.String() case 'e': selField = &selRecord.Email inputPrompt = "Email: " inputMode = true valBuffer.WriteString(selRecord.Email) inputbox.Text = inputPrompt + valBuffer.String() } } else if inputMode && e.Type == termui.EventKey { if e.Key == termui.KeyEnter { if selField != nil { *selField = valBuffer.String() } valBuffer.Reset() inputMode = false inputbox.Text = "" rlist := getRecordList(safe) recordlist.Items = rlist[startIndex:] } else if e.Key == termui.KeyEsc { valBuffer.Reset() inputMode = false inputbox.Text = "" } else if e.Key == termui.KeySpace { valBuffer.WriteRune(' ') } else if e.Key == termui.KeyBackspace || e.Ch == '' { s := valBuffer.String() valBuffer = bytes.Buffer{} if len(s) > 0 { s = s[0 : len(s)-1] } valBuffer.WriteString(s) inputbox.Text = inputPrompt + valBuffer.String() } else { valBuffer.WriteRune(e.Ch) inputbox.Text = inputPrompt + valBuffer.String() } } if e.Type == termui.EventResize { termui.Body.Width = termui.TermWidth() termui.Body.Align() } if selRecord != nil { recorddetail.Text = getRecordDetail(*selRecord) } if inputMode { termui.Body.Rows[2] = inputrow } else { termui.Body.Rows[2] = commandrow } termui.Body.Align() termui.Render(termui.Body) } } oerr := pwsafe.OutputFile(*pfile, string(pw), *safe) if oerr != nil { log.Fatalln(oerr) } }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() ui.UseTheme("helloworld") p := ui.NewPar(":PRESS q TO QUIT DEMO") p.Height = 3 p.Width = 50 p.Border.Label = "Text Box" 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.Border.Label = "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.Border.Label = "Gauge" spark := ui.NewSparkline() 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} spark.Data = spdata spark1 := ui.NewSparkline() spark1.Title = "srv 1:" spark1.Data = spdata sp := ui.NewSparklines(spark, spark1) sp.Width = 25 sp.Height = 7 sp.Border.Label = "Sparkline" sp.Y = 4 sp.X = 25 lc := ui.NewLineChart() sinps := (func() []float64 { n := 100 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/4) } return ps })() lc.Border.Label = "Line Chart" lc.Data = sinps lc.Width = 50 lc.Height = 11 lc.X = 0 lc.Y = 14 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.Border.Label = "Bar Chart" bc.Width = 26 bc.Height = 10 bc.X = 51 bc.Y = 0 bc.DataLabels = bclabels lc1 := ui.NewLineChart() lc1.Border.Label = "Line Chart" rndwalk := (func() []float64 { n := 150 d := make([]float64, n) for i := 1; i < n; i++ { if i < 20 { d[i] = d[i-1] + 0.01 } if i > 20 { d[i] = d[i-1] - 0.05 } } return d })() lc1.Data = rndwalk lc1.Width = 26 lc1.Height = 11 lc1.X = 51 lc1.Y = 14 p1 := ui.NewPar("Hey!\nI am a borderless block!") p1.HasBorder = false p1.Width = 26 p1.Height = 2 p1.X = 52 p1.Y = 11 draw := func(t int) { g.Percent = t % 101 list.Items = strs[t%9:] sp.Lines[0].Data = spdata[t%10:] sp.Lines[1].Data = spdata[t/2%10:] lc.Data = sinps[t/2:] lc1.Data = rndwalk[t:] bc.Data = bcdata[t/2%10:] ui.Render(p, list, g, sp, lc, bc, lc1, p1) } evt := ui.EventCh() i := 0 for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } default: draw(i) i++ if i == 102 { return } time.Sleep(time.Second / 2) } } }
func selectConnection(conf *types.Configuration, input string) *types.Connection { if err := ui.Init(); err != nil { panic(err) } defer func() { ui.Close() if e := recover(); e != nil { panic(e) } }() treeView := NewSelectList() treeView.Border.Label = " Connections " debugView := ui.NewPar("") searchView := ui.NewPar(input) searchView.Border.Label = " Search " connectButton := ui.NewPar(" Connect ") menuView := ui.NewRow( ui.NewCol(8, 0, connectButton), ) selectedButton := 0 buttons := []*ui.Par{connectButton} selectButtons := func() { selectedButton %= len(buttons) for i, v := range buttons { if i == selectedButton { v.TextBgColor = ui.ColorBlue } else { v.TextBgColor = ui.ColorDefault } } } selectButtons() ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, treeView)), ui.NewRow( ui.NewCol(12, 0, debugView)), ui.NewRow( ui.NewCol(6, 0, searchView), ui.NewCol(6, 0, menuView))) heights := func() { searchView.Height = 3 connectButton.Height = searchView.Height menuView.Height = searchView.Height debugView.Height = 5 treeView.Height = ui.TermHeight() - searchView.Height - debugView.Height } heights() ui.Body.Align() connectionsIndex := make(map[int]types.Node) pathToIndexMap := make(map[string]int) var distances map[string]int var filteredRoot *types.Container doRefilter := func() { pathToIndexMap := make(map[string]int) distances, _ = filter(conf, input) filteredRoot = filterTree(conf, distances) drawTree(treeView, connectionsIndex, distances, pathToIndexMap, filteredRoot) /*if bestMatchPath != "" { if index, ok := pathToIndexMap[bestMatchPath]; ok { treeView.CurrentSelection = index } }*/ } doRefilter() events := make(chan ui.Event) go func(in <-chan ui.Event, out chan<- ui.Event) { for e := range in { out <- e } close(out) }(ui.EventCh(), events) for { ui.Render(ui.Body) ev := <-events if ev.Err != nil { debugView.Text = ev.Err.Error() } refilter := false switch ev.Type { case ui.EventResize: heights() ui.Body.Width = ev.Width ui.Body.Align() treeView.Debug += " resize" case ui.EventKey: if ev.Key <= ui.KeyHome && ev.Key >= ui.KeyArrowRight { switch ev.Key { case ui.KeyHome: treeView.CurrentSelection = 0 case ui.KeyEnd: treeView.CurrentSelection = len(treeView.Items) - 1 case ui.KeyPgup: treeView.CurrentSelection -= treeView.Height - 3 case ui.KeyPgdn: treeView.CurrentSelection += treeView.Height + 3 case ui.KeyArrowDown: treeView.CurrentSelection++ case ui.KeyArrowUp: treeView.CurrentSelection-- case ui.KeyArrowLeft: selectedButton-- selectButtons() case ui.KeyArrowRight: selectedButton++ selectButtons() } if treeView.CurrentSelection > len(treeView.Items)-1 { treeView.CurrentSelection = len(treeView.Items) - 1 } else if treeView.CurrentSelection < 0 { treeView.CurrentSelection = 0 } } else if ev.Key == ui.KeyEnter { n := connectionsIndex[treeView.CurrentSelection] if c, ok := n.(*types.Connection); ok { if buttons[selectedButton] == connectButton { return c } } else if c, ok := n.(*types.Container); ok { if c.Expanded { c.Expanded = false } else { c.Expanded = true } drawTree(treeView, connectionsIndex, distances, pathToIndexMap, filteredRoot) } } else if ev.Key == ui.KeyEsc || ev.Key == ui.KeyCtrlC { return nil } else if ev.Ch >= ' ' && ev.Ch <= '~' { input += string(ev.Ch) searchView.Text = input refilter = true } else if ev.Key == ui.KeyBackspace || ev.Key == ui.KeyBackspace2 { if len(input) > 0 { input = input[:len(input)-1] searchView.Text = input refilter = true } } } if refilter { doRefilter() } if ev.Err == nil { if DEBUG { debugView.Text = fmt.Sprint(distances) debugView.Text += fmt.Sprintf( " ev: %d key: %x input: %s|\ncur: %d scroll: %d scrolledCur: %d len: %d\ninner: %d align: %s", ev.Type, ev.Key, input, treeView.CurrentSelection, treeView.scroll, treeView.scrolledSelection, len(treeView.Items), treeView.InnerHeight(), treeView.Debug) treeView.Debug = "" } else { n := connectionsIndex[treeView.CurrentSelection] if c, ok := n.(*types.Connection); ok { debugView.Text = fmt.Sprintf("%s %s:%d\n%s", c.Info.Protocol, c.Info.Host, c.Info.Port, c.Info.Description) } else if _, ok := n.(*types.Container); ok { debugView.Text = "" } } } } }
func main() { err := termui.Init() if err != nil { panic(err) } defer termui.Close() termui.UseTheme("helloworld") header := termui.NewPar("Press q to quit, Press j or k to switch tabs") header.Height = 1 header.Width = 50 header.HasBorder = false header.TextBgColor = termui.ColorBlue tab1 := extra.NewTab("pierwszy") par2 := termui.NewPar("Press q to quit\nPress j or k to switch tabs\n") par2.Height = 5 par2.Width = 37 par2.Y = 0 par2.Border.Label = "Keys" par2.Border.FgColor = termui.ColorYellow tab1.AddBlocks(par2) tab2 := extra.NewTab("drugi") 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.Border.Label = "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 tab2.AddBlocks(bc) tab3 := extra.NewTab("trzeci") tab4 := extra.NewTab("żółw") tab5 := extra.NewTab("four") tab6 := extra.NewTab("five") tabpane := extra.NewTabpane() tabpane.Y = 1 tabpane.Width = 30 tabpane.HasBorder = true tabpane.SetTabs(*tab1, *tab2, *tab3, *tab4, *tab5, *tab6) evt := termui.EventCh() termui.Render(header, tabpane) for { select { case e := <-evt: if e.Type == termui.EventKey { switch e.Ch { case 'q': return case 'j': tabpane.SetActiveLeft() termui.Render(header, tabpane) case 'k': tabpane.SetActiveRight() termui.Render(header, tabpane) } } } } }
func main() { err := ui.Init() if 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.Border.Label = "Text Box" p.Border.FgColor = ui.ColorCyan 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.Border.Label = "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.Border.Label = "Gauge" g.BarColor = ui.ColorRed g.Border.FgColor = ui.ColorWhite g.Border.LabelFgColor = 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} 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.Border.Label = "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.Border.Label = "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.Border.Label = "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.Border.Label = "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.HasBorder = 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[t%10:] sp.Lines[1].Data = spdata[t/2%10:] lc.Data = sinps[t/2:] lc1.Data = sinps[2*t:] bc.Data = bcdata[t/2%10:] ui.Render(p, list, g, sp, lc, bc, lc1, p1) } evt := ui.EventCh() i := 0 for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } default: draw(i) i++ if i == 102 { return } time.Sleep(time.Second / 2) } } }
func (env *Env) Stats(cmd *cobra.Command, args []string) { err := ui.Init() if err != nil { panic(err) } defer ui.Close() ui.UseTheme("helloworld") s := ui.NewPar(env.db.Scrobbles()) s.Border.Label = "LocalFM" s.Height = 3 recTracks, err := env.db.RecentTracks() if err != nil { log.Fatalf("Error in RecentTracks:", err) } rec := ui.NewPar(recTracks) rec.Border.Label = "Recent Tracks" rec.Height = (viper.GetInt("main.recent_tracks") + 2) topArtists, err := env.db.TopArtists() if err != nil { log.Fatalf("Error in TopArtists:", err) } topart := ui.NewPar(topArtists) topart.Border.Label = "Top Artists" topart.Height = (viper.GetInt("main.top_artists") + 2) topAlbums, err := env.db.TopAlbums() if err != nil { log.Fatalf("Error in TopAlbums:", err) } topalbs := ui.NewPar(topAlbums) topalbs.Border.Label = "Top Albums" topalbs.Height = (viper.GetInt("main.top_albums") + 2) topSongs, err := env.db.TopSongs() if err != nil { log.Fatalf("Error in TopSongs:", err) } topsongs := ui.NewPar(topSongs) topsongs.Border.Label = "Top Songs" topsongs.Height = (viper.GetInt("main.top_songs") + 2) ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, s)), ui.NewRow( ui.NewCol(12, 0, rec)), ui.NewRow( ui.NewCol(6, 0, topart), ui.NewCol(6, 0, topalbs)), ui.NewRow( ui.NewCol(12, 0, topsongs))) ui.Body.Align() done := make(chan bool) redraw := make(chan bool) update := func() { time.Sleep(time.Second / 2) redraw <- true } evt := ui.EventCh() ui.Render(ui.Body) go update() for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } if e.Type == ui.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() go func() { redraw <- true }() } case <-done: return case <-redraw: ui.Render(ui.Body) } } }
func (gv *graphicalVisualizer) PrintDistributionChart(rate time.Duration) error { //Initialize termui err := termui.Init() if err != nil { return errors.New("Unable to initalize terminal graphics mode.") //panic(err) } defer termui.Close() if rate <= time.Duration(0) { rate = graphicalRateDelta } termui.UseTheme("helloworld") //Initalize some widgets p := termui.NewPar("Lattice Visualization") if p == nil { return errors.New("Error Initializing termui objects NewPar") } p.Height = 1 p.Width = 25 p.TextFgColor = termui.ColorWhite p.HasBorder = false r := termui.NewPar(fmt.Sprintf("rate:%v", rate)) if r == nil { return errors.New("Error Initializing termui objects NewPar") } r.Height = 1 r.Width = 10 r.TextFgColor = termui.ColorWhite r.HasBorder = false s := termui.NewPar("hit [+=inc; -=dec; q=quit]") if s == nil { return errors.New("Error Initializing termui objects NewPar") } s.Height = 1 s.Width = 30 s.TextFgColor = termui.ColorWhite s.HasBorder = false bg := termui.NewMBarChart() if bg == nil { return errors.New("Error Initializing termui objects NewMBarChart") } bg.IsDisplay = false bg.Data[0] = []int{0} bg.DataLabels = []string{"Missing"} bg.Width = termui.TermWidth() - 10 bg.Height = termui.TermHeight() - 5 bg.BarColor[0] = termui.ColorGreen bg.BarColor[1] = termui.ColorYellow bg.NumColor[0] = termui.ColorRed bg.NumColor[1] = termui.ColorRed bg.TextColor = termui.ColorWhite bg.Border.LabelFgColor = termui.ColorWhite bg.Border.Label = "[X-Axis: Cells; Y-Axis: Instances]" bg.BarWidth = 10 bg.BarGap = 1 bg.ShowScale = true //12 column grid system termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 5, p))) termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, bg))) termui.Body.AddRows(termui.NewRow(termui.NewCol(6, 0, s), termui.NewCol(6, 5, r))) termui.Body.Align() termui.Render(termui.Body) bg.IsDisplay = true clock := clock.NewClock() evt := termui.EventCh() for { select { case e := <-evt: if e.Type == termui.EventKey { switch { case (e.Ch == 'q' || e.Ch == 'Q'): return nil case (e.Ch == '+' || e.Ch == '='): rate += graphicalRateDelta case (e.Ch == '_' || e.Ch == '-'): rate -= graphicalRateDelta if rate <= time.Duration(0) { rate = graphicalRateDelta } } r.Text = fmt.Sprintf("rate:%v", rate) termui.Render(termui.Body) } if e.Type == termui.EventResize { termui.Body.Width = termui.TermWidth() termui.Body.Align() termui.Render(termui.Body) } case <-clock.NewTimer(rate).C(): err := gv.getProgressBars(bg) if err != nil { return err } termui.Render(termui.Body) } } return nil }
func Run(cliConnection plugin.CliConnection, args []string) { if len(args) == 0 { helper.CallCommandHelp("statistics", "Incorrect usage.\n") os.Exit(1) } var debugOutput, fullOutput bool for _, arg := range args[1:] { switch arg { case "--debug": debugOutput = true case "--full": fullOutput = true } } appName := args[0] appGuid := getAppGuid(cliConnection, appName) statsChan := make(chan Statistics) errChan := make(chan error) defer close(statsChan) defer close(errChan) go pollStats(cliConnection, appGuid, statsChan, errChan) // setup ui if !debugOutput { if err := newTerminalUI(appName); err != nil { fmt.Println("\nERROR:", err) os.Exit(1) } defer term.Close() } // main loop var nofInstances int for { select { // ui events case e := <-ui.EventCh(): if e.Type == ui.EventKey { if e.Ch == 'q' || e.Key == ui.KeyCtrlC { term.Close() os.Exit(0) } else if e.Key == ui.KeyPgup { // ui shows max 8 instances if nofInstances < 8 { scaleApp(cliConnection, appName, nofInstances+1) } } else if e.Key == ui.KeyPgdn { if nofInstances > 1 { scaleApp(cliConnection, appName, nofInstances-1) } } } if e.Type == ui.EventResize { term.Resize() } if e.Type == ui.EventError { term.Close() fmt.Println("\nERROR:", e.Err) os.Exit(0) } case stats := <-statsChan: nofInstances = len(stats.Instances) // print to stdout if --debug is set if debugOutput { for _, idx := range stats.Instances { var data interface{} // print only usage metrics if --full is not set data = stats.Data[idx].Stats.Usage if fullOutput { data = stats.Data[idx] } output, err := json.Marshal(data) if err != nil { fmt.Println("\nERROR:", err) os.Exit(1) } fmt.Printf("{\"instance_index\":\"%s\",\"metrics\":%v}\n", idx, string(output)) } } else { // render terminal dashboard term.UpdateStatistics(stats) } case err := <-errChan: if !debugOutput { term.Close() } fmt.Println("\nERROR:", err) os.Exit(1) case <-time.After(time.Second * 15): if !debugOutput { term.Close() } fmt.Println("\nTIMEOUT") fmt.Println("Querying metrics took too long.. Check your connectivity!") os.Exit(1) } } }
// StartUI periodically refreshes the screen using recent data func StartUI( opts map[string]interface{}, statsCh chan *Stats, shutdownCh chan struct{}, ) { cleanStats := &Stats{ Varz: &gnatsd.Varz{}, Connz: &gnatsd.Connz{}, Rates: &Rates{}, } // Show empty values on first display text := generateParagraph(opts, cleanStats) par := ui.NewPar(text) par.Height = ui.TermHeight() par.Width = ui.TermWidth() par.HasBorder = false helpText := generateHelp() helpPar := ui.NewPar(helpText) helpPar.Height = ui.TermHeight() helpPar.Width = ui.TermWidth() helpPar.HasBorder = false // Top like view paraRow := ui.NewRow(ui.NewCol(ui.TermWidth(), 0, par)) // Help view helpParaRow := ui.NewRow(ui.NewCol(ui.TermWidth(), 0, helpPar)) // Create grids that we'll be using to toggle what to render topViewGrid := ui.NewGrid(paraRow) helpViewGrid := ui.NewGrid(helpParaRow) // Start with the topviewGrid by default ui.Body.Rows = topViewGrid.Rows ui.Body.Align() // Used to toggle back to previous mode viewMode := TopViewMode // Used for pinging the IU to refresh the screen with new values redraw := make(chan struct{}) update := func() { for { stats := <-statsCh // Update top view text text = generateParagraph(opts, stats) par.Text = text redraw <- struct{}{} } } // Flags for capturing options waitingSortOption := false waitingLimitOption := false displaySubscriptions := false optionBuf := "" refreshOptionHeader := func() { // Need to mask what was typed before clrline := "\033[1;1H\033[6;1H " clrline += " " for i := 0; i < len(optionBuf); i++ { clrline += " " } fmt.Printf(clrline) } evt := ui.EventCh() ui.Render(ui.Body) go update() for { select { case e := <-evt: if waitingSortOption { if e.Type == ui.EventKey && e.Key == ui.KeyEnter { sortOpt := gnatsd.SortOpt(optionBuf) switch sortOpt { case SortByCid, SortBySubs, SortByPending, SortByOutMsgs, SortByInMsgs, SortByOutBytes, SortByInBytes: opts["sort"] = sortOpt default: go func() { // Has to be at least of the same length as sort by header emptyPadding := " " fmt.Printf("\033[1;1H\033[6;1Hinvalid order: %s%s", optionBuf, emptyPadding) waitingSortOption = false time.Sleep(1 * time.Second) refreshOptionHeader() optionBuf = "" }() continue } refreshOptionHeader() waitingSortOption = false optionBuf = "" continue } // Handle backspace if e.Type == ui.EventKey && len(optionBuf) > 0 && (e.Key == ui.KeyBackspace || e.Key == ui.KeyBackspace2) { optionBuf = optionBuf[:len(optionBuf)-1] refreshOptionHeader() } else { optionBuf += string(e.Ch) } fmt.Printf("\033[1;1H\033[6;1Hsort by [%s]: %s", opts["sort"], optionBuf) } if waitingLimitOption { if e.Type == ui.EventKey && e.Key == ui.KeyEnter { var n int _, err := fmt.Sscanf(optionBuf, "%d", &n) if err == nil { opts["conns"] = n } waitingLimitOption = false optionBuf = "" refreshOptionHeader() continue } // Handle backspace if e.Type == ui.EventKey && len(optionBuf) > 0 && (e.Key == ui.KeyBackspace || e.Key == ui.KeyBackspace2) { optionBuf = optionBuf[:len(optionBuf)-1] refreshOptionHeader() } else { optionBuf += string(e.Ch) } fmt.Printf("\033[1;1H\033[6;1Hlimit [%d]: %s", opts["conns"], optionBuf) } if e.Type == ui.EventKey && (e.Ch == 'q' || e.Key == ui.KeyCtrlC) { close(shutdownCh) cleanExit() } if e.Type == ui.EventKey && e.Ch == 's' && !(waitingLimitOption || waitingSortOption) { if displaySubscriptions { displaySubscriptions = false opts["subs"] = false } else { displaySubscriptions = true opts["subs"] = true } } if e.Type == ui.EventKey && viewMode == HelpViewMode { ui.Body.Rows = topViewGrid.Rows viewMode = TopViewMode continue } if e.Type == ui.EventKey && e.Ch == 'o' && !waitingLimitOption && viewMode == TopViewMode { fmt.Printf("\033[1;1H\033[6;1Hsort by [%s]:", opts["sort"]) waitingSortOption = true } if e.Type == ui.EventKey && e.Ch == 'n' && !waitingSortOption && viewMode == TopViewMode { fmt.Printf("\033[1;1H\033[6;1Hlimit [%d]:", opts["conns"]) waitingLimitOption = true } if e.Type == ui.EventKey && (e.Ch == '?' || e.Ch == 'h') && !(waitingSortOption || waitingLimitOption) { if viewMode == TopViewMode { refreshOptionHeader() optionBuf = "" } ui.Body.Rows = helpViewGrid.Rows viewMode = HelpViewMode waitingLimitOption = false waitingSortOption = false } if e.Type == ui.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() go func() { redraw <- struct{}{} }() } case <-redraw: ui.Render(ui.Body) } } }