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
|
||||
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