diff --git a/README.md b/README.md index 562935c..43e4cf3 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Another terminal based graphical activity monitor, inspired by [gtop](https://gi + @@ -95,6 +96,8 @@ To make a custom colorscheme, check out the [template](./colorschemes/template.g `-v`, `--version` Show version. `-p`, `--percpu` Show each CPU in the CPU widget. `-a`, `--averagecpu` Show average CPU in the CPU widget. +`-b`, `--bar` Show a statusbar with the time. +`-t`, `--battery` Show battery level (defaults to false, `minimal` turns off) ## Building deb/rpms @@ -118,6 +121,7 @@ This will place the built packages into the `dist` folder. - [exrook/drawille-go](https://github.com/exrook/drawille-go) - [shirou/gopsutil](https://github.com/shirou/gopsutil) - [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser) +- [battery](https://github.com/distatus/battery) ## Stargazers over time diff --git a/assets/battery.png b/assets/battery.png new file mode 100644 index 0000000..b70f2ab Binary files /dev/null and b/assets/battery.png differ diff --git a/colorschemes/default.go b/colorschemes/default.go index 48db2d3..de65c22 100644 --- a/colorschemes/default.go +++ b/colorschemes/default.go @@ -9,6 +9,8 @@ var Default = Colorscheme{ CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + MainMem: 5, SwapMem: 11, diff --git a/colorschemes/default.json b/colorschemes/default.json index 5d26a8b..99abfaa 100644 --- a/colorschemes/default.json +++ b/colorschemes/default.json @@ -9,6 +9,8 @@ "CPULines": [4, 3, 2, 1, 5, 6, 7, 8], + "BattLines": [4, 3, 2, 1, 5, 6, 7, 8], + "MainMem": 5, "SwapMem": 11, diff --git a/colorschemes/default_dark.go b/colorschemes/default_dark.go index 15f7137..6070985 100644 --- a/colorschemes/default_dark.go +++ b/colorschemes/default_dark.go @@ -9,6 +9,8 @@ var DefaultDark = Colorscheme{ CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + MainMem: 5, SwapMem: 3, diff --git a/colorschemes/monokai.go b/colorschemes/monokai.go index b3dbc23..445f054 100644 --- a/colorschemes/monokai.go +++ b/colorschemes/monokai.go @@ -9,6 +9,8 @@ var Monokai = Colorscheme{ CPULines: []int{81, 70, 208, 197, 249, 141, 221, 186}, + BattLines: []int{81, 70, 208, 197, 249, 141, 221, 186}, + MainMem: 208, SwapMem: 186, diff --git a/colorschemes/solarized.go b/colorschemes/solarized.go index 2ead4df..3ce9997 100644 --- a/colorschemes/solarized.go +++ b/colorschemes/solarized.go @@ -9,6 +9,8 @@ var Solarized = Colorscheme{ CPULines: []int{61, 33, 37, 64, 125, 160, 166, 136}, + BattLines: []int{61, 33, 37, 64, 125, 160, 166, 136}, + MainMem: 125, SwapMem: 166, diff --git a/colorschemes/template.go b/colorschemes/template.go index d303e4b..f410e61 100644 --- a/colorschemes/template.go +++ b/colorschemes/template.go @@ -30,6 +30,8 @@ type Colorscheme struct { // should add at least 8 here CPULines []int + BattLines []int + MainMem int SwapMem int diff --git a/go.mod b/go.mod index d0daf08..4366d90 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ require ( github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd github.com/davecgh/go-spew v1.1.1 // indirect + github.com/distatus/battery v0.0.0-20170521010419-916919eb43bd github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815 github.com/gizak/termui v0.0.0-20190101100649-ffdef4cb72e9 github.com/go-ole/go-ole v1.2.1 // indirect diff --git a/go.sum b/go.sum index 7b1034c..7043b02 100644 --- a/go.sum +++ b/go.sum @@ -1,34 +1,35 @@ +github.com/0xAX/notificator v0.0.0-20181105090803-d81462e38c21/go.mod h1:NtXa9WwQsukMHZpjNakTTz0LArxvGYdPA9CjIcUSZ6s= github.com/ProtonMail/go-appdir v0.0.0-20180220133335-7c788d1b45c6 h1:de/SvQsi6Oou9TJYp6Kp17S+JjXGn1w8XVYWFlE0z/U= github.com/ProtonMail/go-appdir v0.0.0-20180220133335-7c788d1b45c6/go.mod h1:3d8Y9F5mbEUjrYbcJ3rcDxcWbqbttF+011nVZmdRdzc= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd h1:nSJpATLVvFa19BEHX4ys+VGNWfI4FUGMweEI6QXs8wg= github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/cjbassi/termui v0.0.0-20181208033036-e8dd23f6146c h1:vcaCtK8ObawtpQRW8GdbKZ+eJGEUn41xJ8Snagd/c6I= +github.com/cjbassi/termui v0.0.0-20181208033036-e8dd23f6146c/go.mod h1:rqXckrwz+i0fH/zNwU6AdBNULHwmZsgehnSlhKP5i2Q= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distatus/battery v0.0.0-20170521010419-916919eb43bd h1:rxw7AZpSwNgPPFdxDNSwQ+TfvOjmSGDK6tlpY7vw9bw= +github.com/distatus/battery v0.0.0-20170521010419-916919eb43bd/go.mod h1:gGO7GxHTi1zlRT+cAj8uGG0/8HFiqAeH0TJvoipnuPs= github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815 h1:HMAfwOa33y82IaQEKQDfUCiwNlxtM1iw7HLM9ru0RNc= github.com/docopt/docopt.go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:l7JNRynTRuqe45tpIyItHNqZWTxywYjp87MWTOnU5cg= -github.com/gizak/termui v0.0.0-20190101005313-46c77dca8480 h1:+NHS7QUnQqEwIuhrHaFT6R78LMGbja4fYTu6wny7Q4s= -github.com/gizak/termui v0.0.0-20190101005313-46c77dca8480/go.mod h1:S3xz8JHXNDPSNFsvXCdG7bHlEGrwvUG3a0joR/xYZ5M= -github.com/gizak/termui v0.0.0-20190101093801-cb2e49106b0d h1:+4uQfMi8fK2KnydfTqUW9wuRLfNVkzz+LuH7EHPUwxA= -github.com/gizak/termui v0.0.0-20190101093801-cb2e49106b0d/go.mod h1:S3xz8JHXNDPSNFsvXCdG7bHlEGrwvUG3a0joR/xYZ5M= github.com/gizak/termui v0.0.0-20190101100649-ffdef4cb72e9 h1:h5eo3CW6c9WMG+rN8cVxf25v8bSWFjuaDJdvtEWc61E= github.com/gizak/termui v0.0.0-20190101100649-ffdef4cb72e9/go.mod h1:S3xz8JHXNDPSNFsvXCdG7bHlEGrwvUG3a0joR/xYZ5M= -github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/gizak/termui v2.3.0+incompatible h1:S8wJoNumYfc/rR5UezUM4HsPEo3RJh0LKdiuDWQpjqw= +github.com/gizak/termui v2.3.0+incompatible/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/maruel/panicparse v1.1.1 h1:k62YPcEoLncEEpjMt92GtG5ugb8WL/510Ys3/h5IkRc= +github.com/maruel/panicparse v1.1.1/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI= github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb h1:YahEjAGkJtCrkqgVHhX6n8ZX+CZ3hDRL9fjLYugLfSs= github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shirou/gopsutil v2.18.11+incompatible h1:PMFTKnFTr/YTRW5rbLK4vWALV3a+IGXse5nvhSjztmg= github.com/shirou/gopsutil v2.18.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20180406135729-3b87a42e500a h1:DwI0ihryIiWlRUKL/ii7Snvn4LiL9TvMoVZq3qMbffg= golang.org/x/sys v0.0.0-20180406135729-3b87a42e500a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6 h1:IcgEB62HYgAhX0Nd/QrVgZlxlcyxbGQHElLUhW2X4Fo= +golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/main.go b/main.go index e1e5007..869cedc 100644 --- a/main.go +++ b/main.go @@ -32,8 +32,8 @@ var ( zoomInterval = 3 helpVisible = false averageLoad = false + battery = false percpuLoad = false - widgetCount = 6 fahrenheit = false configDir = appdir.New("gotop").UserConfig() logPath = filepath.Join(configDir, "errors.log") @@ -43,6 +43,7 @@ var ( termHeight int cpu *w.CPU + batt *w.Batt mem *w.Mem proc *w.Proc net *w.Net @@ -65,6 +66,7 @@ Options: -p, --percpu Show each CPU in the CPU widget. -a, --averagecpu Show average CPU in the CPU widget. -f, --fahrenheit Show temperatures in fahrenheit. + -t, --battery Show battery charge over time ('minimal' disables; widget updates slowly) -b, --bar Show a statusbar with the time. Colorschemes: @@ -86,11 +88,9 @@ Colorschemes: } averageLoad, _ = args["--averagecpu"].(bool) percpuLoad, _ = args["--percpu"].(bool) + battery, _ = args["--battery"].(bool) minimal, _ = args["--minimal"].(bool) - if minimal { - widgetCount = 3 - } statusbar, _ = args["--bar"].(bool) @@ -168,8 +168,17 @@ func setupGrid() { rowHeight = 50.0 / 151 barRow = ui.NewRow(1.0/151, w.NewStatusBar()) } + var cpuRow ui.GridItem + if battery { + cpuRow = ui.NewRow(rowHeight, + ui.NewCol(2.0/3, cpu), + ui.NewCol(1.0/3, batt), + ) + } else { + cpuRow = ui.NewRow(rowHeight, cpu) + } grid.Set( - ui.NewRow(rowHeight, cpu), + cpuRow, ui.NewRow(rowHeight, ui.NewCol(1.0/3, ui.NewRow(1.0/2, disk), @@ -215,6 +224,24 @@ func widgetColors() { } if !minimal { + if battery { + var battKeys []string + for key := range batt.Data { + battKeys = append(battKeys, key) + } + sort.Strings(battKeys) + i = 0 // Re-using variable from CPU + for _, v := range battKeys { + if i >= len(colorscheme.BattLines) { + // assuming colorscheme for battery lines is not empty + i = 0 + } + c := colorscheme.BattLines[i] + batt.LineColor[v] = ui.Attribute(c) + i++ + } + } + temp.TempLow = ui.Attribute(colorscheme.TempLow) temp.TempHigh = ui.Attribute(colorscheme.TempHigh) @@ -227,29 +254,41 @@ func widgetColors() { func initWidgets() { var wg sync.WaitGroup - wg.Add(widgetCount) + wg.Add(1) go func() { cpu = w.NewCPU(interval, zoom, averageLoad, percpuLoad) wg.Done() }() + wg.Add(1) go func() { mem = w.NewMem(interval, zoom) wg.Done() }() + wg.Add(1) go func() { proc = w.NewProc() wg.Done() }() if !minimal { + if battery { + wg.Add(1) + go func() { + batt = w.NewBatt(time.Minute, zoom) + wg.Done() + }() + } + wg.Add(1) go func() { net = w.NewNet() wg.Done() }() + wg.Add(1) go func() { disk = w.NewDisk() wg.Done() }() + wg.Add(1) go func() { temp = w.NewTemp(fahrenheit) wg.Done() diff --git a/src/widgets/battery.go b/src/widgets/battery.go new file mode 100644 index 0000000..271de65 --- /dev/null +++ b/src/widgets/battery.go @@ -0,0 +1,64 @@ +package widgets + +import ( + "fmt" + "log" + "math" + "strconv" + "time" + + ui "github.com/cjbassi/gotop/src/termui" + "github.com/distatus/battery" +) + +type Batt struct { + *ui.LineGraph + Count int // number of batteries + interval time.Duration +} + +func NewBatt(interval time.Duration, zoom int) *Batt { + batts, err := battery.GetAll() + self := &Batt{ + LineGraph: ui.NewLineGraph(), + Count: len(batts), + interval: interval, + } + self.Title = "Battery Status" + self.Zoom = zoom + if err != nil { + log.Printf("failed to get battery info from system: %v", err) + } + for i, b := range batts { + pc := math.Abs(b.Current/b.Full) * 100.0 + self.Data[mkId(i)] = []float64{pc} + } + + self.update() + + go func() { + ticker := time.NewTicker(self.interval) + for range ticker.C { + self.update() + } + }() + + return self +} + +func mkId(i int) string { + return "Batt" + strconv.Itoa(i) +} + +func (self *Batt) update() { + batts, err := battery.GetAll() + if err != nil { + log.Printf("failed to get battery info from system: %v", err) + } + for i, b := range batts { + n := mkId(i) + pc := math.Abs(b.Current/b.Full) * 100.0 + self.Data[n] = append(self.Data[n], pc) + self.Labels[n] = fmt.Sprintf("%3.0f%% %.0f/%.0f", pc, math.Abs(b.Current), math.Abs(b.Full)) + } +}