Skip to content

Commit d76d56b

Browse files
committed
Initial waybar plugin framework for go
Signed-off-by: Jim Ramsay <[email protected]>
1 parent 1abd545 commit d76d56b

File tree

7 files changed

+217
-1
lines changed

7 files changed

+217
-1
lines changed

Diff for: README.md

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,44 @@
11
# gowaybarplug
2-
Go framework for
2+
3+
Go framework for custom [Waybar](https://github.com/Alexays/Waybar) plugins
4+
5+
# Usage
6+
7+
First build a plugin that reports some interesting status:
8+
9+
```go
10+
package main
11+
12+
import (
13+
"time"
14+
15+
waybar "github.com/lack/gowaybarplug"
16+
)
17+
18+
main() {
19+
updater := waybar.NewUpdater()
20+
for {
21+
status := waybar.Status{
22+
Text: "Some text",
23+
Toolbar: "Other text",
24+
}
25+
// Obviously do something more interesting than just static text in the status...
26+
updater.Status <- &status
27+
time.Sleep(15 * time.Second)
28+
}
29+
}
30+
```
31+
32+
Then add it to your ~/.config/waybar/config:
33+
34+
```json
35+
{
36+
// ... Other waybar config
37+
"custom/mything": {
38+
"format": "{} {icon}",
39+
"return-type": "json",
40+
"exec": "/path/to/my/new/plugin"
41+
// etc
42+
}
43+
}
44+
```

Diff for: go.mod

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module github.com/lack/gowaybarplug
2+
3+
go 1.18
4+
5+
require (
6+
github.com/davecgh/go-spew v1.1.1 // indirect
7+
github.com/pmezard/go-difflib v1.0.0 // indirect
8+
github.com/stretchr/objx v0.4.0 // indirect
9+
github.com/stretchr/testify v1.8.0 // indirect
10+
github.com/xorcare/pointer v1.1.0 // indirect
11+
gopkg.in/yaml.v3 v3.0.1 // indirect
12+
)

Diff for: go.sum

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
6+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7+
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
8+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
9+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
10+
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
11+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
12+
github.com/xorcare/pointer v1.1.0 h1:sFwXOhRF8QZ0tyVZrtxWGIoVZNEmRzBCaFWdONPQIUM=
13+
github.com/xorcare/pointer v1.1.0/go.mod h1:6KLhkOh6YbuvZkT4YbxIbR/wzLBjyMxOiNzZhJTor2Y=
14+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
15+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
16+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
17+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Diff for: status.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package gowaybarplug
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
)
7+
8+
// Status represents the json structure expected from waybar custom plugins.
9+
// See waybar-custom(5) for more details.
10+
type Status struct {
11+
// Text is usually the label, represented by {} in a waybar format
12+
Text string `json:"text"`
13+
// Tooltip appears when you mouse-hover over the custom entry
14+
Tooltip string `json:"tooltip,omitempty"`
15+
// Class is a list of css classes that will be added to the waybat entry
16+
Class []string `json:"class,omitempty"`
17+
// 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.
18+
Percentage *int `json:"percentage,omitempty"`
19+
// Alt os the key used to look up the {icon} of format-icons is specified as a map.
20+
Alt string `json:"alt,omitempty"`
21+
}
22+
23+
// String renders the Status as a json string
24+
func (s *Status) String() string {
25+
b, err := json.Marshal(s)
26+
if err != nil {
27+
// Fake json error reporting
28+
return fmt.Sprintf(`"text": "Marshal error", "tooltip": "Marshal error: %s"}`, err.Error())
29+
}
30+
return string(b)
31+
}

Diff for: status_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package gowaybarplug
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/xorcare/pointer"
8+
)
9+
10+
func TestString(t *testing.T) {
11+
tests := []struct {
12+
input Status
13+
output string
14+
}{{
15+
input: Status{},
16+
output: `{"text":""}`,
17+
}, {
18+
input: Status{
19+
Text: "a",
20+
Tooltip: "b",
21+
Class: []string{"c1", "c2"},
22+
Percentage: pointer.Int(42),
23+
Alt: "d",
24+
},
25+
output: `{"text":"a","tooltip":"b","class":["c1","c2"],"percentage":42,"alt":"d"}`,
26+
}}
27+
for _, test := range tests {
28+
assert.Equal(t, test.input.String(), test.output)
29+
}
30+
}

Diff for: updater.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package gowaybarplug
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
// Updater runs a goroutine that accepts Status updates in a channel and ptints them to stdout.
10+
type Updater struct {
11+
// Status is the main Status reporting channel. Every Status submitted here will be sent to stdout.
12+
Status chan *Status
13+
14+
last string
15+
writer io.Writer
16+
}
17+
18+
// Create a new Updater and start the receiver thread
19+
func NewUpdater() *Updater {
20+
u := Updater{
21+
Status: make(chan *Status, 10),
22+
writer: os.Stdout,
23+
}
24+
go u.run()
25+
return &u
26+
}
27+
28+
func (u *Updater) run() {
29+
for s := range u.Status {
30+
next := s.String()
31+
if next != u.last {
32+
u.last = next
33+
fmt.Fprintln(u.writer, next)
34+
}
35+
}
36+
}
37+
38+
func (u *Updater) OutputTo(writer io.Writer) *Updater {
39+
u.writer = writer
40+
return u
41+
}

Diff for: updater_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package gowaybarplug
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
type ChBuf struct {
12+
Ch chan bool
13+
Buff bytes.Buffer
14+
}
15+
16+
func NewChBuf() *ChBuf {
17+
return &ChBuf{
18+
Ch: make(chan bool, 100),
19+
}
20+
}
21+
22+
func (c *ChBuf) Write(data []byte) (int, error) {
23+
n, err := c.Buff.Write(data)
24+
c.Ch <- err == nil
25+
return n, err
26+
}
27+
28+
func (c *ChBuf) WaitForBuffer(deadline time.Duration) {
29+
select {
30+
case <-c.Ch:
31+
case <-time.After(deadline):
32+
}
33+
}
34+
35+
func TestNewUpdater(t *testing.T) {
36+
buff := NewChBuf()
37+
u := NewUpdater().OutputTo(buff)
38+
u.Ch <- &Status{Text: "test"}
39+
buff.WaitForBuffer(2 * time.Second)
40+
result, err := buff.Buff.ReadString('\n')
41+
assert.NoError(t, err)
42+
assert.Equal(t, result, "{\"text\":\"test\"}\n")
43+
}

0 commit comments

Comments
 (0)