Initial waybar plugin framework for go
Signed-off-by: Jim Ramsay <i.am@jimramsay.com>
This commit is contained in:
parent
1abd54534b
commit
d76d56b393
7 changed files with 217 additions and 1 deletions
44
README.md
44
README.md
|
@ -1,2 +1,44 @@
|
||||||
# gowaybarplug
|
# gowaybarplug
|
||||||
Go framework for
|
|
||||||
|
Go framework for custom [Waybar](https://github.com/Alexays/Waybar) plugins
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
First build a plugin that reports some interesting status:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
waybar "github.com/lack/gowaybarplug"
|
||||||
|
)
|
||||||
|
|
||||||
|
main() {
|
||||||
|
updater := waybar.NewUpdater()
|
||||||
|
for {
|
||||||
|
status := waybar.Status{
|
||||||
|
Text: "Some text",
|
||||||
|
Toolbar: "Other text",
|
||||||
|
}
|
||||||
|
// Obviously do something more interesting than just static text in the status...
|
||||||
|
updater.Status <- &status
|
||||||
|
time.Sleep(15 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then add it to your ~/.config/waybar/config:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// ... Other waybar config
|
||||||
|
"custom/mything": {
|
||||||
|
"format": "{} {icon}",
|
||||||
|
"return-type": "json",
|
||||||
|
"exec": "/path/to/my/new/plugin"
|
||||||
|
// etc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
12
go.mod
Normal file
12
go.mod
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module github.com/lack/gowaybarplug
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/stretchr/objx v0.4.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.8.0 // indirect
|
||||||
|
github.com/xorcare/pointer v1.1.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
17
go.sum
Normal file
17
go.sum
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/xorcare/pointer v1.1.0 h1:sFwXOhRF8QZ0tyVZrtxWGIoVZNEmRzBCaFWdONPQIUM=
|
||||||
|
github.com/xorcare/pointer v1.1.0/go.mod h1:6KLhkOh6YbuvZkT4YbxIbR/wzLBjyMxOiNzZhJTor2Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
31
status.go
Normal file
31
status.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package gowaybarplug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status represents the json structure expected from waybar custom plugins.
|
||||||
|
// See waybar-custom(5) for more details.
|
||||||
|
type Status struct {
|
||||||
|
// Text is usually the label, represented by {} in a waybar format
|
||||||
|
Text string `json:"text"`
|
||||||
|
// Tooltip appears when you mouse-hover over the custom entry
|
||||||
|
Tooltip string `json:"tooltip,omitempty"`
|
||||||
|
// Class is a list of css classes that will be added to the waybat entry
|
||||||
|
Class []string `json:"class,omitempty"`
|
||||||
|
// Percentage can be added to format strings via the {percent} format string, but can also affect which icon is set in {icon} if the config specifies format-icons as an array.
|
||||||
|
Percentage *int `json:"percentage,omitempty"`
|
||||||
|
// Alt os the key used to look up the {icon} of format-icons is specified as a map.
|
||||||
|
Alt string `json:"alt,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String renders the Status as a json string
|
||||||
|
func (s *Status) String() string {
|
||||||
|
b, err := json.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
// Fake json error reporting
|
||||||
|
return fmt.Sprintf(`"text": "Marshal error", "tooltip": "Marshal error: %s"}`, err.Error())
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
30
status_test.go
Normal file
30
status_test.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package gowaybarplug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/xorcare/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input Status
|
||||||
|
output string
|
||||||
|
}{{
|
||||||
|
input: Status{},
|
||||||
|
output: `{"text":""}`,
|
||||||
|
}, {
|
||||||
|
input: Status{
|
||||||
|
Text: "a",
|
||||||
|
Tooltip: "b",
|
||||||
|
Class: []string{"c1", "c2"},
|
||||||
|
Percentage: pointer.Int(42),
|
||||||
|
Alt: "d",
|
||||||
|
},
|
||||||
|
output: `{"text":"a","tooltip":"b","class":["c1","c2"],"percentage":42,"alt":"d"}`,
|
||||||
|
}}
|
||||||
|
for _, test := range tests {
|
||||||
|
assert.Equal(t, test.input.String(), test.output)
|
||||||
|
}
|
||||||
|
}
|
41
updater.go
Normal file
41
updater.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package gowaybarplug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Updater runs a goroutine that accepts Status updates in a channel and ptints them to stdout.
|
||||||
|
type Updater struct {
|
||||||
|
// Status is the main Status reporting channel. Every Status submitted here will be sent to stdout.
|
||||||
|
Status chan *Status
|
||||||
|
|
||||||
|
last string
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Updater and start the receiver thread
|
||||||
|
func NewUpdater() *Updater {
|
||||||
|
u := Updater{
|
||||||
|
Status: make(chan *Status, 10),
|
||||||
|
writer: os.Stdout,
|
||||||
|
}
|
||||||
|
go u.run()
|
||||||
|
return &u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Updater) run() {
|
||||||
|
for s := range u.Status {
|
||||||
|
next := s.String()
|
||||||
|
if next != u.last {
|
||||||
|
u.last = next
|
||||||
|
fmt.Fprintln(u.writer, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Updater) OutputTo(writer io.Writer) *Updater {
|
||||||
|
u.writer = writer
|
||||||
|
return u
|
||||||
|
}
|
43
updater_test.go
Normal file
43
updater_test.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package gowaybarplug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChBuf struct {
|
||||||
|
Ch chan bool
|
||||||
|
Buff bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChBuf() *ChBuf {
|
||||||
|
return &ChBuf{
|
||||||
|
Ch: make(chan bool, 100),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChBuf) Write(data []byte) (int, error) {
|
||||||
|
n, err := c.Buff.Write(data)
|
||||||
|
c.Ch <- err == nil
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChBuf) WaitForBuffer(deadline time.Duration) {
|
||||||
|
select {
|
||||||
|
case <-c.Ch:
|
||||||
|
case <-time.After(deadline):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewUpdater(t *testing.T) {
|
||||||
|
buff := NewChBuf()
|
||||||
|
u := NewUpdater().OutputTo(buff)
|
||||||
|
u.Ch <- &Status{Text: "test"}
|
||||||
|
buff.WaitForBuffer(2 * time.Second)
|
||||||
|
result, err := buff.Buff.ReadString('\n')
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, result, "{\"text\":\"test\"}\n")
|
||||||
|
}
|
Reference in a new issue