//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 (p *TicketShowPage) Create() { log.Debugf("TicketShowPage.Create(): self: %s (%p)", p.Id(), p) log.Debugf("TicketShowPage.Create(): currentPage: %s (%p)", currentPage.Id(), currentPage) p.opts = getJiraOpts() if p.TicketId == "" { p.TicketId = ticketListPage.GetSelectedTicketId() } if p.MaxWrapWidth == 0 { if m := p.opts["max_wrap"]; m != nil { p.MaxWrapWidth = uint(m.(int64)) } else { p.MaxWrapWidth = defaultMaxWrapWidth } } ui.Clear() ls := ui.NewList() if p.statusBar == nil { p.statusBar = new(StatusBar) } if p.commandBar == nil { p.commandBar = commandBar } p.uiList = ls if p.Template == "" { if templateOpt := p.opts["template"]; templateOpt == nil { p.Template = "jira_ui_view" } else { p.Template = templateOpt.(string) } } innerWidth := uint(ui.TermWidth()) - 3 if innerWidth < p.MaxWrapWidth { p.WrapWidth = innerWidth } else { p.WrapWidth = p.MaxWrapWidth } if p.apiBody == nil { p.apiBody, _ = FetchJiraTicket(p.TicketId) } p.cachedResults = WrapText(JiraTicketAsStrings(p.apiBody, p.Template), p.WrapWidth) p.displayLines = make([]string, len(p.cachedResults)) if p.selectedLine >= len(p.cachedResults) { p.selectedLine = len(p.cachedResults) - 1 } ls.ItemFgColor = ui.ColorYellow ls.Height = ui.TermHeight() - 2 ls.Width = ui.TermWidth() ls.Border = true ls.BorderLabel = fmt.Sprintf("%s %s", p.TicketId, p.ticketTrailAsString()) ls.Y = 0 p.statusBar.Create() p.commandBar.Create() p.Update() }
func (p *LabelListPage) Create() { ui.Clear() ls := ui.NewList() p.uiList = ls if p.statusBar == nil { p.statusBar = new(StatusBar) } if p.commandBar == nil { p.commandBar = commandBar } queryName := p.ActiveQuery.Name queryJQL := p.ActiveQuery.JQL p.labelCounts = countLabelsFromQuery(queryJQL) p.cachedResults = p.labelsAsSortedList() p.isPopulated = true p.displayLines = make([]string, len(p.cachedResults)) ls.ItemFgColor = ui.ColorYellow ls.BorderLabel = fmt.Sprintf("Label view -- %s: %s", queryName, queryJQL) ls.Height = ui.TermHeight() - 2 ls.Width = ui.TermWidth() ls.Y = 0 p.statusBar.Create() p.commandBar.Create() p.Update() }
func (ed *Editor) resize() { termui.Body.Width = termui.TermWidth() ed.applets.Height = termui.TermHeight() - 2 + 1 // offset 1 for border ed.desc.Y = ed.locked.Y + ed.locked.Height - 1 // offset 1 for border ed.desc.Height = termui.TermHeight() - ed.desc.Y - 2 ed.title.Y = termui.TermHeight() - 2 ed.title.Width = termui.TermWidth() + 1 // offset 1 for border ed.appinfo.Width = termui.TermWidth() - ed.appinfo.X + 1 // offset 1 for border ed.locked.Width = termui.TermWidth() - ed.applets.Width + 1 // offset 1 for border ed.desc.Width = termui.TermWidth() - ed.applets.Width + 1 // offset 1 for border ed.desc.WrapLength = ed.desc.Width termui.Render(ed.applets, ed.fields, ed.appinfo, ed.locked, ed.desc, ed.title) }
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 (p *TicketListPage) Create() { log.Debugf("TicketListPage.Create(): self: %s (%p)", p.Id(), p) log.Debugf("TicketListPage.Create(): currentPage: %s (%p)", currentPage.Id(), currentPage) ui.Clear() ls := ui.NewList() p.uiList = ls if p.statusBar == nil { p.statusBar = new(StatusBar) } if p.commandBar == nil { p.commandBar = commandBar } query := p.ActiveQuery.JQL if sort := p.ActiveSort.JQL; sort != "" { re := regexp.MustCompile(`(?i)\s+ORDER\s+BY.+$`) query = re.ReplaceAllString(query, ``) + " " + sort } if len(p.cachedResults) == 0 { p.cachedResults = JiraQueryAsStrings(query, p.ActiveQuery.Template) } if p.selectedLine >= len(p.cachedResults) { p.selectedLine = len(p.cachedResults) - 1 } p.displayLines = make([]string, len(p.cachedResults)) ls.ItemFgColor = ui.ColorYellow ls.BorderLabel = fmt.Sprintf("%s: %s", p.ActiveQuery.Name, p.ActiveQuery.JQL) ls.Height = ui.TermHeight() - 2 ls.Width = ui.TermWidth() ls.Y = 0 p.statusBar.Create() p.commandBar.Create() p.Update() }
func NewUi() Ui { headerWidget := termui.NewPar(fmt.Sprintf("podcastd v%s\nCopyright 2015 Philippe Gerber\nhttps://github.com/bigwhoop/podcastd", VERSION)) headerWidget.Height = 5 headerWidget.HasBorder = false headerWidget.PaddingTop = 1 headerWidget.PaddingBottom = 1 headerWidget.PaddingLeft = 1 infoWidget := termui.NewPar("") infoWidget.HasBorder = false infoWidget.Text = fmt.Sprintf("Press 'q' to quit") feedsWidget := termui.NewList() feedsWidget.Border.Label = "Feeds" return Ui{ termui.TermWidth(), headerWidget, infoWidget, feedsWidget, make(map[string]bool, 0), make([]*termui.Gauge, 0), make(map[string]curl.ProgressStatus, 0), } }
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 (p *CommandBar) Create() { ls := ui.NewList() p.uiList = ls ls.ItemFgColor = ui.ColorGreen ls.Border = false ls.Height = 1 ls.Width = ui.TermWidth() ls.X = 0 ls.Y = ui.TermHeight() - 1 p.Update() }
func adjustDimensions() { termui.Body.Width = termui.TermWidth() height := termui.TermHeight() parMap["moveHistory"].Height = height - 23 - 4 parMap["output"].Height = height - 23 if height < 31 { parMap["board"].Height = height - 8 parMap["moveHistory"].Height = 2 parMap["output"].Height = 6 } }
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 (p *StatusBar) Create() { ls := ui.NewList() p.uiList = ls ls.ItemFgColor = ui.ColorWhite ls.ItemBgColor = ui.ColorRed ls.Bg = ui.ColorRed ls.Border = false ls.Height = 1 ls.Width = ui.TermWidth() ls.X = 0 ls.Y = ui.TermHeight() - 2 p.Update() }
func (p *BaseListPage) Create() { ui.Clear() ls := ui.NewList() p.uiList = ls p.cachedResults = make([]string, 0) p.displayLines = make([]string, len(p.cachedResults)) ls.ItemFgColor = ui.ColorYellow ls.BorderLabel = "Updating, please wait" ls.Height = ui.TermHeight() ls.Width = ui.TermWidth() ls.Y = 0 p.Update() }
func (p *BaseInputBox) Create() { ls := ui.NewList() var strs []string p.uiList = ls ls.Items = strs ls.ItemFgColor = ui.ColorGreen ls.BorderFg = ui.ColorRed ls.Height = 1 ls.Width = 30 ls.Overflow = "wrap" ls.X = ui.TermWidth()/2 - ls.Width/2 ls.Y = ui.TermHeight()/2 - ls.Height/2 p.Update() }
func (p *PasswordInputBox) Create() { ls := ui.NewList() p.uiList = ls var strs []string ls.Items = strs ls.ItemFgColor = ui.ColorGreen ls.BorderLabel = "Enter Password:" ls.BorderFg = ui.ColorRed ls.Height = 3 ls.Width = 30 ls.X = ui.TermWidth()/2 - ls.Width/2 ls.Y = ui.TermHeight()/2 - ls.Height/2 p.Update() }
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() { 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 (p *SortOrderPage) Create() { ls := ui.NewList() p.uiList = ls p.selectedLine = 0 p.firstDisplayLine = 0 if len(p.cachedResults) == 0 { p.cachedResults = getSorts() p.displayLines = make([]string, len(p.cachedResults)) } ls.ItemFgColor = ui.ColorGreen ls.BorderLabel = "Sort By..." ls.BorderFg = ui.ColorRed ls.Height = 10 ls.Width = 50 ls.X = ui.TermWidth()/2 - ls.Width/2 ls.Y = ui.TermHeight()/2 - ls.Height/2 p.Update() }
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 loadStats() { var max = ui.TermWidth() s, err := fetchStats() if err != nil { displayMsg(fmt.Sprintf("error fetching stats: %v", err)) return } displayMsg("") var cnts = []struct { cnt int titleFmt string }{ {s.Goroutine, "goroutines (%d)"}, {s.Thread, "threads (%d)"}, } for i, v := range cnts { if n := len(sp.Lines[i].Data); n > max { sp.Lines[i].Data = sp.Lines[i].Data[n-max : n] } sp.Lines[i].Title = fmt.Sprintf(v.titleFmt, v.cnt) sp.Lines[i].Data = append(sp.Lines[i].Data, v.cnt) } }
func (p *HelpPage) Create() { ui.Clear() ls := ui.NewList() p.uiList = ls if p.statusBar == nil { p.statusBar = new(StatusBar) } if p.commandBar == nil { p.commandBar = commandBar } if len(p.cachedResults) == 0 { p.cachedResults = HelpTextAsStrings(nil, "jira_ui_help") } p.displayLines = make([]string, len(p.cachedResults)) ls.ItemFgColor = ui.ColorYellow ls.BorderLabel = "Help" ls.Height = ui.TermHeight() - 2 ls.Width = ui.TermWidth() ls.Y = 0 p.statusBar.Create() p.commandBar.Create() p.Update() }
func (p *QueryPage) Create() { log.Debugf("QueryPage.Create(): self: %s (%p)", p.Id(), p) log.Debugf("QueryPage.Create(): currentPage: %s (%p)", currentPage.Id(), currentPage) ui.Clear() ls := ui.NewList() p.uiList = ls if p.statusBar == nil { p.statusBar = new(StatusBar) } if p.commandBar == nil { p.commandBar = commandBar } p.cachedResults = getQueries() p.displayLines = make([]string, len(p.cachedResults)) ls.ItemFgColor = ui.ColorYellow ls.BorderLabel = "Queries" ls.Height = ui.TermHeight() - 2 ls.Width = ui.TermWidth() ls.Y = 0 p.statusBar.Create() p.commandBar.Create() p.Update() }
// Relayout recalculates widgets sizes and coords. func (t *TermUISingle) Relayout() { tw, th := termui.TermWidth(), termui.TermHeight() h := th // First row: Title and Status pars firstRowH := 3 t.Title.Height = firstRowH t.Title.Width = tw / 2 if tw%2 == 1 { t.Title.Width++ } t.Status.Height = firstRowH t.Status.Width = tw / 2 t.Status.X = t.Title.X + t.Title.Width h -= firstRowH // Second row: lists secondRowH := 3 num := len(t.Pars) parW := tw / num for i, par := range t.Pars { par.Y = th - h par.Width = parW par.Height = secondRowH par.X = i * parW } if num*parW < tw { t.Pars[num-1].Width = tw - ((num - 1) * parW) } h -= secondRowH // Third row: Sparklines t.Sparkline.Width = tw t.Sparkline.Height = h t.Sparkline.Y = th - h }
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() }
// 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() { 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) } }
// 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() { // Init err := ui.Init() if err != nil { panic(err) } defer ui.Close() // Theme Setting ui.UseTheme("helloworld") // Setup the CPU Gauge cpuGauge := ui.NewGauge() cpuGauge.Height = 2 cpuGauge.BarColor = ui.ColorRed cpuGauge.HasBorder = false cpuGauge.PaddingBottom = 1 go UpdateGenericGauge(cpuGauge, GetCPUPercentage) // Setup the RAM Gauge ramGauge := ui.NewGauge() ramGauge.Height = 2 ramGauge.BarColor = ui.ColorGreen ramGauge.HasBorder = false ramGauge.PaddingBottom = 1 go UpdateGenericGauge(ramGauge, GetRAMPercentage) // Setup the Label list ls := ui.NewList() ls.HasBorder = false ls.Items = []string{ "CPU", "", "RAM", } ls.Height = 5 // Setup the CPU Line Chart cpuLineChart := ui.NewLineChart() cpuLineChart.Width = 50 cpuLineChart.Height = 11 cpuLineChart.Border.Label = "CPU Usage" cpuLineChart.AxesColor = ui.ColorWhite cpuLineChart.LineColor = ui.ColorGreen | ui.AttrBold go UpdateGenericChart(cpuLineChart, GetCPUPercentage) // Setup the RAM Line Chart ramLineChart := ui.NewLineChart() ramLineChart.Width = 50 ramLineChart.Height = 11 ramLineChart.Border.Label = "RAM Usage" ramLineChart.AxesColor = ui.ColorWhite ramLineChart.LineColor = ui.ColorGreen | ui.AttrBold go UpdateGenericChart(ramLineChart, GetRAMPercentage) // Setup the layout ui.Body.AddRows( ui.NewRow( ui.NewCol(3, 0, cpuGauge, ramGauge), ui.NewCol(3, 0, ls), ), ui.NewRow( ui.NewCol(6, 0, cpuLineChart), ui.NewCol(6, 0, ramLineChart), ), ) // Align ui.Body.Align() // Create the event polling system evt := make(chan tm.Event) go func() { for { evt <- tm.PollEvent() } }() for { select { case e := <-evt: if e.Type == tm.EventKey && e.Ch == 'q' { return } if e.Type == tm.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() } default: ui.Render(ui.Body) time.Sleep(time.Second / 2) } } }