2018-02-19 15:25:02 +08:00
package main
import (
2018-12-11 13:21:40 +08:00
"fmt"
2020-02-18 01:40:16 +08:00
"io"
2018-12-05 13:44:25 +08:00
"log"
2020-02-18 23:44:29 +08:00
"net/http"
2018-02-19 15:25:02 +08:00
"os"
"os/signal"
2018-12-05 13:44:25 +08:00
"path/filepath"
2020-04-23 23:41:20 +08:00
"sort"
2020-02-13 23:40:20 +08:00
"strings"
2018-02-19 15:25:02 +08:00
"syscall"
"time"
2020-04-28 02:53:45 +08:00
//_ "net/http/pprof"
2019-03-08 15:15:41 +08:00
ui "github.com/gizak/termui/v3"
2020-02-18 23:44:29 +08:00
"github.com/prometheus/client_golang/prometheus/promhttp"
2020-03-07 23:03:25 +08:00
"github.com/shibukawa/configdir"
2020-04-28 08:38:58 +08:00
flag "github.com/xxxserxxx/opflag"
2019-02-07 09:18:44 +08:00
2020-04-24 03:07:08 +08:00
"github.com/xxxserxxx/gotop/v4"
"github.com/xxxserxxx/gotop/v4/colorschemes"
"github.com/xxxserxxx/gotop/v4/devices"
"github.com/xxxserxxx/gotop/v4/layout"
"github.com/xxxserxxx/gotop/v4/logging"
2020-04-28 09:33:41 +08:00
"github.com/xxxserxxx/gotop/v4/widgets"
2020-04-24 03:07:08 +08:00
w "github.com/xxxserxxx/gotop/v4/widgets"
2018-02-19 15:25:02 +08:00
)
2019-01-13 08:31:37 +08:00
const (
graphHorizontalScaleDelta = 3
2020-03-04 04:16:28 +08:00
defaultUI = "2:cpu\ndisk/1 2:mem/2\ntemp\n2:net 2:procs"
2020-02-14 03:24:41 +08:00
minimalUI = "cpu\nmem procs"
2020-02-16 06:10:45 +08:00
batteryUI = "cpu/2 batt/1\ndisk/1 2:mem/2\ntemp\nnet procs"
2020-02-29 00:03:41 +08:00
procsUI = "cpu 4:procs\ndisk\nmem\nnet"
2020-03-07 19:01:47 +08:00
kitchensink = "3:cpu/2 3:mem/1\n4:temp/1 3:disk/2\npower\n3:net 3:procs"
2019-01-13 08:31:37 +08:00
)
2018-02-19 15:25:02 +08:00
var (
2020-04-28 09:33:41 +08:00
// Version of the program; set during build from git tags
Version = "0.0.0"
// BuildDate when the program was compiled; set during build
2020-04-23 23:41:20 +08:00
BuildDate = "Hadean"
2020-02-14 00:15:52 +08:00
conf gotop . Config
2020-02-13 10:15:49 +08:00
help * w . HelpMenu
bar * w . StatusBar
statusbar bool
2018-12-05 13:44:25 +08:00
stderrLogger = log . New ( os . Stderr , "" , 0 )
2018-02-19 15:25:02 +08:00
)
2020-02-18 01:40:16 +08:00
func parseArgs ( conf * gotop . Config ) error {
2020-04-07 00:04:08 +08:00
cds := conf . ConfigDir . QueryFolders ( configdir . All )
cpaths := make ( [ ] string , len ( cds ) )
for i , p := range cds {
cpaths [ i ] = p . Path
}
2020-04-28 02:53:45 +08:00
help := flag . BoolP ( "help" , "h" , false , "Show this screen." )
color := flag . StringP ( "color" , "c" , conf . Colorscheme . Name , "Set a colorscheme." )
flag . IntVarP ( & conf . GraphHorizontalScale , "graphscale" , "S" , conf . GraphHorizontalScale , "Graph scale factor, >0" )
version := flag . BoolP ( "version" , "v" , false , "Print version and exit." )
versioN := flag . BoolP ( "" , "V" , false , "Print version and exit." )
flag . BoolVarP ( & conf . PercpuLoad , "percpu" , "p" , conf . PercpuLoad , "Show each CPU in the CPU widget." )
flag . BoolVarP ( & conf . AverageLoad , "averagecpu" , "a" , conf . AverageLoad , "Show average CPU in the CPU widget." )
fahrenheit := flag . BoolP ( "fahrenheit" , "f" , conf . TempScale == 'F' , "Show temperatures in fahrenheit.Show temperatures in fahrenheit." )
flag . BoolVarP ( & conf . Statusbar , "statusbar" , "s" , conf . Statusbar , "Show a statusbar with the time." )
flag . DurationVarP ( & conf . UpdateInterval , "rate" , "r" , conf . UpdateInterval , "Number of times per second to update CPU and Mem widgets." )
2020-04-28 08:38:58 +08:00
flag . StringVarP ( & conf . Layout , "layout" , "l" , conf . Layout , ` Name of layout spec file for the UI. Use "-" to pipe. ` )
2020-04-28 02:53:45 +08:00
flag . StringVarP ( & conf . NetInterface , "interface" , "i" , "all" , "Select network interface. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using `!`" )
flag . StringVarP ( & conf . ExportPort , "export" , "x" , conf . ExportPort , "Enable metrics for export on the specified port." )
flag . BoolVarP ( & conf . Mbps , "mbps" , "" , conf . Mbps , "Show network rate as mbps." )
// FIXME Where did this go??
//conf.Band = flag.IntP("bandwidth", "B", 100, "Specify the number of bits per seconds.")
flag . BoolVar ( & conf . Test , "test" , conf . Test , "Runs tests and exits with success/failure code." )
list := flag . String ( "list" , "" , ` List < devices | layouts | colorschemes | paths | keys >
2020-04-28 08:38:58 +08:00
devices : Prints out device names for filterable widgets
layouts : Lists build - in layouts
colorschemes : Lists built - in colorschemes
paths : List out configuration file search paths
keys : Show the keyboard bindings . ` )
2020-04-28 02:53:45 +08:00
wc := flag . Bool ( "write-config" , false , "Write out a default config file." )
2020-04-28 08:38:58 +08:00
flag . SortFlags = false
2020-04-28 02:53:45 +08:00
flag . Usage = func ( ) {
fmt . Fprintf ( os . Stderr , "Usage: %s [options]\n\nOptions:\n" , os . Args [ 0 ] )
flag . PrintDefaults ( )
}
flag . Parse ( )
if * version || * versioN {
fmt . Printf ( "gotop %s (%s)\n" , Version , BuildDate )
os . Exit ( 0 )
2018-09-19 04:42:49 +08:00
}
2020-04-28 02:53:45 +08:00
if * help {
flag . Usage ( )
os . Exit ( 0 )
2020-03-02 23:09:17 +08:00
}
2020-04-28 02:53:45 +08:00
cs , err := colorschemes . FromName ( conf . ConfigDir , * color )
if err != nil {
return err
2020-04-16 22:36:10 +08:00
}
2020-04-28 02:53:45 +08:00
conf . Colorscheme = cs
if * fahrenheit {
conf . TempScale = 'F'
} else {
conf . TempScale = 'C'
2020-04-17 02:28:18 +08:00
}
2020-04-28 02:53:45 +08:00
if * list != "" {
switch * list {
2020-04-23 23:41:20 +08:00
case "layouts" :
2020-04-28 09:33:41 +08:00
fmt . Println ( _layouts )
2020-04-23 23:41:20 +08:00
case "colorschemes" :
2020-04-28 09:33:41 +08:00
fmt . Println ( _colorschemes )
2020-04-23 23:41:20 +08:00
case "paths" :
fmt . Println ( "Loadable colorschemes & layouts, and the config file, are searched for, in order:" )
paths := make ( [ ] string , 0 )
for _ , d := range conf . ConfigDir . QueryFolders ( configdir . All ) {
paths = append ( paths , d . Path )
}
fmt . Println ( strings . Join ( paths , "\n" ) )
fmt . Printf ( "\nThe log file is in %s\n" , filepath . Join ( conf . ConfigDir . QueryCacheFolder ( ) . Path , logging . LOGFILE ) )
case "devices" :
listDevices ( )
case "keys" :
2020-04-28 09:33:41 +08:00
fmt . Println ( widgets . KEYBINDS )
2020-04-23 23:41:20 +08:00
default :
2020-04-28 08:38:58 +08:00
fmt . Printf ( "Unknown option \"%s\"; try layouts, colorschemes, keys, paths, or devices\n" , * list )
2020-04-23 23:41:20 +08:00
os . Exit ( 1 )
}
os . Exit ( 0 )
}
2020-04-28 02:53:45 +08:00
if * wc {
2020-04-23 23:41:20 +08:00
path , err := conf . Write ( )
if err != nil {
fmt . Printf ( "Failed to write configuration file: %s\n" , err )
os . Exit ( 1 )
}
fmt . Printf ( "Config written to %s\n" , path )
2020-03-08 02:14:19 +08:00
os . Exit ( 0 )
}
2020-02-18 01:40:16 +08:00
return nil
2018-02-19 15:25:02 +08:00
}
2020-02-14 00:15:52 +08:00
func setDefaultTermuiColors ( c gotop . Config ) {
2020-02-13 10:15:49 +08:00
ui . Theme . Default = ui . NewStyle ( ui . Color ( c . Colorscheme . Fg ) , ui . Color ( c . Colorscheme . Bg ) )
ui . Theme . Block . Title = ui . NewStyle ( ui . Color ( c . Colorscheme . BorderLabel ) , ui . Color ( c . Colorscheme . Bg ) )
ui . Theme . Block . Border = ui . NewStyle ( ui . Color ( c . Colorscheme . BorderLine ) , ui . Color ( c . Colorscheme . Bg ) )
2018-02-19 15:25:02 +08:00
}
2020-02-14 00:15:52 +08:00
func eventLoop ( c gotop . Config , grid * layout . MyGrid ) {
2020-02-13 10:15:49 +08:00
drawTicker := time . NewTicker ( c . UpdateInterval ) . C
2018-02-19 15:25:02 +08:00
2018-11-30 10:17:13 +08:00
// handles kill signal sent to gotop
sigTerm := make ( chan os . Signal , 2 )
signal . Notify ( sigTerm , os . Interrupt , syscall . SIGTERM )
2018-02-19 15:25:02 +08:00
2018-11-30 10:17:13 +08:00
uiEvents := ui . PollEvents ( )
2018-02-21 19:41:40 +08:00
2018-11-30 10:17:13 +08:00
previousKey := ""
2018-02-19 15:25:02 +08:00
2018-11-30 10:17:13 +08:00
for {
select {
case <- sigTerm :
return
case <- drawTicker :
2020-02-13 10:15:49 +08:00
if ! c . HelpVisible {
2019-03-08 15:43:10 +08:00
ui . Render ( grid )
2019-03-17 22:54:56 +08:00
if statusbar {
ui . Render ( bar )
}
2018-11-30 10:17:13 +08:00
}
case e := <- uiEvents :
2020-02-14 23:35:58 +08:00
if grid . Proc != nil && grid . Proc . HandleEvent ( e ) {
ui . Render ( grid . Proc )
break
}
2018-11-30 10:17:13 +08:00
switch e . ID {
case "q" , "<C-c>" :
return
case "?" :
2020-02-13 10:15:49 +08:00
c . HelpVisible = ! c . HelpVisible
2019-01-08 12:10:09 +08:00
case "<Resize>" :
payload := e . Payload . ( ui . Resize )
2019-02-07 09:18:44 +08:00
termWidth , termHeight := payload . Width , payload . Height
2019-02-02 15:22:27 +08:00
if statusbar {
2019-02-07 09:18:44 +08:00
grid . SetRect ( 0 , 0 , termWidth , termHeight - 1 )
bar . SetRect ( 0 , termHeight - 1 , termWidth , termHeight )
2019-02-02 15:22:27 +08:00
} else {
grid . SetRect ( 0 , 0 , payload . Width , payload . Height )
}
2019-01-08 12:10:09 +08:00
help . Resize ( payload . Width , payload . Height )
ui . Clear ( )
}
2020-02-13 10:15:49 +08:00
if c . HelpVisible {
2019-01-08 12:10:09 +08:00
switch e . ID {
case "?" :
2018-02-19 15:25:02 +08:00
ui . Clear ( )
ui . Render ( help )
2019-01-08 12:10:09 +08:00
case "<Escape>" :
2020-02-13 10:15:49 +08:00
c . HelpVisible = false
2019-03-08 15:43:10 +08:00
ui . Render ( grid )
2019-01-08 12:10:09 +08:00
case "<Resize>" :
ui . Render ( help )
2018-02-19 15:25:02 +08:00
}
2019-01-08 12:10:09 +08:00
} else {
switch e . ID {
case "?" :
2019-03-08 15:43:10 +08:00
ui . Render ( grid )
2019-01-08 12:10:09 +08:00
case "h" :
2020-02-13 10:15:49 +08:00
c . GraphHorizontalScale += graphHorizontalScaleDelta
for _ , item := range grid . Lines {
item . Scale ( c . GraphHorizontalScale )
}
ui . Render ( grid )
2019-01-08 12:10:09 +08:00
case "l" :
2020-02-13 10:15:49 +08:00
if c . GraphHorizontalScale > graphHorizontalScaleDelta {
c . GraphHorizontalScale -= graphHorizontalScaleDelta
for _ , item := range grid . Lines {
item . Scale ( c . GraphHorizontalScale )
ui . Render ( item )
}
2018-11-30 10:17:13 +08:00
}
2020-04-17 02:28:18 +08:00
case "b" :
if grid . Net != nil {
grid . Net . Mbps = ! grid . Net . Mbps
}
2019-01-08 12:10:09 +08:00
case "<Resize>" :
2019-03-08 15:43:10 +08:00
ui . Render ( grid )
2019-02-06 18:11:41 +08:00
if statusbar {
2019-03-08 15:43:10 +08:00
ui . Render ( bar )
2019-02-06 18:11:41 +08:00
}
2019-01-08 12:10:09 +08:00
case "<MouseLeft>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
payload := e . Payload . ( ui . Mouse )
grid . Proc . HandleClick ( payload . X , payload . Y )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "k" , "<Up>" , "<MouseWheelUp>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollUp ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "j" , "<Down>" , "<MouseWheelDown>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollDown ( )
ui . Render ( grid . Proc )
}
2019-02-02 15:22:27 +08:00
case "<Home>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollTop ( )
ui . Render ( grid . Proc )
}
2019-02-02 15:06:57 +08:00
case "g" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
if previousKey == "g" {
grid . Proc . ScrollTop ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
}
case "G" , "<End>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollBottom ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "<C-d>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollHalfPageDown ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "<C-u>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollHalfPageUp ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "<C-f>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollPageDown ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "<C-b>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ScrollPageUp ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "d" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
if previousKey == "d" {
2020-02-14 03:38:45 +08:00
grid . Proc . KillProc ( "SIGTERM" )
}
}
case "3" :
if grid . Proc != nil {
if previousKey == "d" {
grid . Proc . KillProc ( "SIGQUIT" )
}
}
case "9" :
if grid . Proc != nil {
if previousKey == "d" {
grid . Proc . KillProc ( "SIGKILL" )
2020-02-13 10:15:49 +08:00
}
2019-01-08 12:10:09 +08:00
}
case "<Tab>" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ToggleShowingGroupedProcs ( )
ui . Render ( grid . Proc )
}
2019-01-08 12:10:09 +08:00
case "m" , "c" , "p" :
2020-02-13 10:15:49 +08:00
if grid . Proc != nil {
grid . Proc . ChangeProcSortMethod ( w . ProcSortMethod ( e . ID ) )
ui . Render ( grid . Proc )
}
2020-02-14 23:35:58 +08:00
case "/" :
if grid . Proc != nil {
grid . Proc . SetEditingFilter ( true )
ui . Render ( grid . Proc )
}
2018-11-30 10:17:13 +08:00
}
2019-01-08 12:10:09 +08:00
if previousKey == e . ID {
previousKey = ""
} else {
previousKey = e . ID
2018-02-19 15:25:02 +08:00
}
}
2018-12-05 13:07:14 +08:00
2018-02-19 15:25:02 +08:00
}
2018-11-30 10:17:13 +08:00
}
}
2018-02-19 15:25:02 +08:00
2020-04-23 23:41:20 +08:00
// TODO: Add fans
2020-02-20 00:40:45 +08:00
// TODO: mpd visualizer widget
2020-04-28 02:53:45 +08:00
// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
// TODO: state:merge #135 linux console font (cmatsuoka/console-font)
// TODO: Abstract out the UI toolkit. mum4k/termdash, VladimirMarkelov/clui, gcla/gowid, rivo/tview, marcusolsson/tui-go might work better for some OS/Archs. Performance/memory use comparison would be interesting.
// TODO: all of the go vet stuff, more unit tests, benchmarks, finish remote.
// TODO: color bars for memory, a-la bashtop
2018-12-10 13:19:09 +08:00
func main ( ) {
2020-04-28 02:53:45 +08:00
// For performance testing
//go func() {
// log.Fatal(http.ListenAndServe(":7777", nil))
//}()
2020-03-08 21:30:06 +08:00
// This is just to make sure gotop returns a useful exit code, but also
// executes all defer statements and so cleans up before exit. Sort of
// annoying work-around for a lack of a clean way to exit Go programs
// with exit codes.
ec := run ( )
2020-03-08 21:50:20 +08:00
if ec > 0 {
if ec < 2 {
fmt . Printf ( "errors encountered; check the log file %s\n" , filepath . Join ( conf . ConfigDir . QueryCacheFolder ( ) . Path , logging . LOGFILE ) )
}
}
2020-03-08 21:30:06 +08:00
os . Exit ( ec )
}
func run ( ) int {
2020-04-28 08:38:58 +08:00
conf := gotop . NewConfig ( )
2020-03-07 23:03:25 +08:00
// Find the config file; look in (1) local, (2) user, (3) global
err := conf . Load ( )
if err != nil {
2020-03-08 21:50:20 +08:00
fmt . Printf ( "failed to parse config file: %s\n" , err )
return 2
2020-02-18 01:40:16 +08:00
}
// Override with command line arguments
2020-03-07 23:03:25 +08:00
err = parseArgs ( & conf )
2020-02-13 10:15:49 +08:00
if err != nil {
2020-03-08 21:50:20 +08:00
fmt . Printf ( "parsing CLI args: %s\n" , err )
return 2
2018-12-11 13:21:40 +08:00
}
2020-02-16 04:27:31 +08:00
logfile , err := logging . New ( conf )
2019-01-20 11:37:31 +08:00
if err != nil {
2020-03-07 23:03:25 +08:00
fmt . Printf ( "failed to setup log file: %v\n" , err )
2020-03-08 21:50:20 +08:00
return 2
2019-01-20 11:37:31 +08:00
}
2019-02-07 09:18:44 +08:00
defer logfile . Close ( )
2019-01-20 11:37:31 +08:00
2020-03-07 23:03:25 +08:00
lstream , err := getLayout ( conf )
if err != nil {
2020-03-08 21:50:20 +08:00
stderrLogger . Print ( err )
2020-03-08 21:30:06 +08:00
return 1
2020-03-07 23:03:25 +08:00
}
2020-03-02 23:09:17 +08:00
ly := layout . ParseLayout ( lstream )
if conf . Test {
2020-03-08 21:30:06 +08:00
return runTests ( conf )
2020-03-02 23:09:17 +08:00
}
2020-04-28 08:38:58 +08:00
errs := devices . Startup ( conf . ExtensionVars )
if len ( errs ) > 0 {
for _ , err := range errs {
stderrLogger . Print ( err )
}
return 1
}
2020-04-28 09:33:41 +08:00
if err = ui . Init ( ) ; err != nil {
2020-03-08 21:50:20 +08:00
stderrLogger . Print ( err )
return 1
2018-11-30 10:17:13 +08:00
}
defer ui . Close ( )
2018-12-11 13:21:40 +08:00
2020-02-13 10:15:49 +08:00
setDefaultTermuiColors ( conf ) // done before initializing widgets to allow inheriting colors
help = w . NewHelpMenu ( )
if statusbar {
bar = w . NewStatusBar ( )
}
2019-01-13 08:44:12 +08:00
2020-02-13 10:15:49 +08:00
grid , err := layout . Layout ( ly , conf )
if err != nil {
2020-03-08 21:50:20 +08:00
stderrLogger . Print ( err )
return 1
2020-02-13 10:15:49 +08:00
}
2019-01-20 11:37:31 +08:00
2019-01-24 13:23:35 +08:00
termWidth , termHeight := ui . TerminalDimensions ( )
2019-02-02 15:22:27 +08:00
if statusbar {
grid . SetRect ( 0 , 0 , termWidth , termHeight - 1 )
} else {
grid . SetRect ( 0 , 0 , termWidth , termHeight )
}
2019-01-01 08:55:50 +08:00
help . Resize ( termWidth , termHeight )
ui . Render ( grid )
2019-02-02 15:22:27 +08:00
if statusbar {
bar . SetRect ( 0 , termHeight - 1 , termWidth , termHeight )
ui . Render ( bar )
}
2018-12-11 13:21:40 +08:00
2020-02-18 23:44:29 +08:00
if conf . ExportPort != "" {
go func ( ) {
http . Handle ( "/metrics" , promhttp . Handler ( ) )
http . ListenAndServe ( conf . ExportPort , nil )
} ( )
}
2020-04-16 22:36:10 +08:00
2020-02-13 10:15:49 +08:00
eventLoop ( conf , grid )
2020-03-08 21:30:06 +08:00
return 0
2018-02-19 15:25:02 +08:00
}
2020-02-18 01:40:16 +08:00
2020-03-07 23:03:25 +08:00
func getLayout ( conf gotop . Config ) ( io . Reader , error ) {
2020-02-18 01:40:16 +08:00
switch conf . Layout {
case "-" :
2020-03-07 23:03:25 +08:00
return os . Stdin , nil
2020-02-18 01:40:16 +08:00
case "default" :
2020-03-07 23:03:25 +08:00
return strings . NewReader ( defaultUI ) , nil
2020-02-18 01:40:16 +08:00
case "minimal" :
2020-03-07 23:03:25 +08:00
return strings . NewReader ( minimalUI ) , nil
2020-02-18 01:40:16 +08:00
case "battery" :
2020-03-07 23:03:25 +08:00
return strings . NewReader ( batteryUI ) , nil
2020-02-29 00:03:41 +08:00
case "procs" :
2020-03-07 23:03:25 +08:00
return strings . NewReader ( procsUI ) , nil
2020-03-07 19:01:47 +08:00
case "kitchensink" :
2020-03-07 23:03:25 +08:00
return strings . NewReader ( kitchensink ) , nil
2020-02-18 01:40:16 +08:00
default :
2020-03-07 23:03:25 +08:00
folder := conf . ConfigDir . QueryFolderContainsFile ( conf . Layout )
if folder == nil {
paths := make ( [ ] string , 0 )
for _ , d := range conf . ConfigDir . QueryFolders ( configdir . Existing ) {
paths = append ( paths , d . Path )
2020-02-18 01:40:16 +08:00
}
2020-03-07 23:03:25 +08:00
return nil , fmt . Errorf ( "unable find layout file %s in %s" , conf . Layout , strings . Join ( paths , ", " ) )
}
lo , err := folder . ReadFile ( conf . Layout )
if err != nil {
return nil , err
2020-02-18 01:40:16 +08:00
}
2020-03-07 23:03:25 +08:00
return strings . NewReader ( string ( lo ) ) , nil
2020-02-18 01:40:16 +08:00
}
}
2020-02-29 00:03:41 +08:00
2020-03-02 23:09:17 +08:00
func runTests ( conf gotop . Config ) int {
fmt . Printf ( "PASS" )
return 0
}
2020-04-23 23:41:20 +08:00
func listDevices ( ) {
ms := devices . Domains
sort . Strings ( ms )
for _ , m := range ms {
fmt . Printf ( "%s:\n" , m )
2020-04-24 02:01:13 +08:00
for _ , d := range devices . Devices ( m , true ) {
2020-04-23 23:41:20 +08:00
fmt . Printf ( "\t%s\n" , d )
}
}
}
2020-04-28 02:53:45 +08:00
2020-04-28 09:33:41 +08:00
const _layouts = ` Built - in layouts :
2020-04-28 08:38:58 +08:00
default
minimal
battery
kitchensink `
2020-04-28 09:33:41 +08:00
const _colorschemes = ` Built - in colorschemes :
2020-04-28 08:38:58 +08:00
default
default - dark ( for white background )
solarized
solarized16 - dark
solarized16 - light
monokai
vice `