diff --git a/i3status/bar.go b/i3status/bar.go new file mode 100644 index 0000000..246868a --- /dev/null +++ b/i3status/bar.go @@ -0,0 +1,38 @@ +package i3status + +import ( + "strings" +) + +type Bar struct { + Input chan Message + Messages map[string]Message +} + +func NewBar(c chan Message) *Bar { + b := Bar{ + Input: c, + Messages: make(map[string]Message), + } + return &b +} + +func (b *Bar) barLoop() { + for { + msg := <-b.Input + b.Messages[msg.Name+msg.Instance] = msg + } +} + +func (b *Bar) Start() { + go b.barLoop() +} + +func (b *Bar) Message() string { + str := "[" + for _, m := range b.Messages { + str += m.ToJson() + ", " + } + + return strings.TrimSuffix(str, ", ") + "]" +} diff --git a/i3status/message.go b/i3status/message.go new file mode 100644 index 0000000..2182c7e --- /dev/null +++ b/i3status/message.go @@ -0,0 +1,36 @@ +package i3status + +import ( + "encoding/json" + "log" +) + +type Message struct { + FullText string `json:"full_text"` + ShortText string `json:"short_text"` + Color string `json:"color"` + MinWidth int `json:"min_width"` + Align string `json:"align"` + Name string `json:"name"` + Instance string `json:"instance"` + Urgent bool `json:"urgent"` + Separator bool `json:"separator"` + SeparatorBlockWidth int `json:"separator_block_width"` +} + +func (m *Message) ToJson() string { + s, err := json.Marshal(m) + if err != nil { + log.Fatal("failed to encode message") + } + + return string(s) +} + +func NewMessage() *Message { + return &Message{ + Separator: true, + Align: "left", + SeparatorBlockWidth: 10, + } +} diff --git a/i3status/widget.go b/i3status/widget.go new file mode 100644 index 0000000..e46ae14 --- /dev/null +++ b/i3status/widget.go @@ -0,0 +1,40 @@ +package i3status + +import ( + "strconv" + "time" +) + +type Widget struct { + Output chan Message + Refresh time.Duration + Instance int +} + +var instanceCount int + +func NewWidget(output chan Message) *Widget { + instanceCount++ + w := Widget{ + Output: output, + Refresh: 1000, + Instance: instanceCount, + } + return &w +} + +func (w *Widget) basicLoop() { + msg := NewMessage() + msg.FullText = "Basic Widget" + msg.Name = "Basic" + msg.Color = "#ffffff" + msg.Instance = strconv.Itoa(w.Instance) + for { + w.Output <- *msg + time.Sleep(w.Refresh * time.Millisecond) + } +} + +func (w *Widget) Start() { + go w.basicLoop() +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..3966445 --- /dev/null +++ b/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "github.com/ghedamat/go-i3status/i3status" + "time" +) + +func main() { + + /* + go func() { + for { + fmt.Println("{\"name\":\"testiii\",\"full_text\":\"ciao\"}") + time.Sleep(1 * time.Second) + } + }() + + go func() { + var i int + for { + fmt.Scanf("%d", &i) + fmt.Println(i) + } + }() + */ + fmt.Println(`{"version":1}`) + fmt.Println("[") + c := make(chan i3status.Message) + b := i3status.NewBar(c) + + w1 := i3status.NewWidget(c) + w2 := i3status.NewWidget(c) + w1.Start() + w2.Start() + b.Start() + + for { + fmt.Println(b.Message() + ",") + time.Sleep(1 * 1e9) + } + +} diff --git a/test/bar_test.go b/test/bar_test.go new file mode 100644 index 0000000..046840b --- /dev/null +++ b/test/bar_test.go @@ -0,0 +1,68 @@ +package i3status_test + +import ( + "github.com/ghedamat/go-i3status/i3status" + . "github.com/smartystreets/goconvey/convey" + "testing" + "time" +) + +func TestBarCreate(t *testing.T) { + Convey("Given a channel", t, func() { + + c := make(chan i3status.Message) + Convey("When a Bar is created", func() { + b := i3status.NewBar(c) + Convey("it has an input channel", func() { + So(b.Input, ShouldEqual, c) + }) + }) + }) +} + +func TestBarStart(t *testing.T) { + Convey("Given a bar", t, func() { + + c := make(chan i3status.Message) + w1 := i3status.NewWidget(c) + w2 := i3status.NewWidget(c) + w1.Start() + w2.Start() + + b := i3status.NewBar(c) + + Convey("When a Bar is started", func() { + b.Start() + Convey("it gets messages from the widgets", func() { + time.Sleep(1 * 1e9) + So(len(b.Messages), ShouldEqual, 2) + }) + }) + }) +} + +func TestBarMessage(t *testing.T) { + Convey("Given a bar", t, func() { + c := make(chan i3status.Message) + b := i3status.NewBar(c) + + Convey("When it's just created", func() { + Convey("it has an empty message", func() { + So(b.Message(), ShouldEqual, "[]") + }) + }) + + Convey("When it's started and widgets are running", func() { + w1 := i3status.NewWidget(c) + w2 := i3status.NewWidget(c) + w1.Start() + w2.Start() + Convey("it has a message", func() { + b.Start() + time.Sleep(1 * 1e9) + json := `[{"full_text":"Basic Widget","short_text":"","color":"#ffffff","min_width":0,"align":"left","name":"Basic","instance":"3","urgent":false,"separator":true,"separator_block_width":10}, {"full_text":"Basic Widget","short_text":"","color":"#ffffff","min_width":0,"align":"left","name":"Basic","instance":"4","urgent":false,"separator":true,"separator_block_width":10}]` + So(b.Message(), ShouldEqual, json) + }) + }) + }) +} diff --git a/test/message_test.go b/test/message_test.go new file mode 100644 index 0000000..6aeb4ab --- /dev/null +++ b/test/message_test.go @@ -0,0 +1,51 @@ +package i3status_test + +import ( + "github.com/ghedamat/go-i3status/i3status" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +var testMsg = i3status.Message{ + FullText: "fullMsg", + ShortText: "shortMsg", + Color: "#ff00ff", + MinWidth: 200, + Align: "center", + Name: "testblock", + Instance: "first", + Urgent: true, + Separator: true, + SeparatorBlockWidth: 20, +} + +func TestHasMessageType(t *testing.T) { + Convey("The message struct exists", t, func() { + So(testMsg.FullText, ShouldEqual, "fullMsg") + }) +} + +func TestConvertMessageToJson(t *testing.T) { + Convey("Given a Message", t, func() { + msg := i3status.Message{FullText: "fullMsg"} + Convey("When a message is converted to json", func() { + json := msg.ToJson() + Convey("valid json is produced", func() { + res := `{"full_text":"fullMsg","short_text":"","color":"","min_width":0,"align":"","name":"","instance":"","urgent":false,"separator":false,"separator_block_width":0}` + So(json, ShouldEqual, res) + }) + }) + }) +} + +func TestMessageConstructor(t *testing.T) { + Convey("Given the Message Constructor", t, func() { + Convey("When a message is created", func() { + msg := i3status.NewMessage() + Convey("it has sane defaults", func() { + So(msg.Separator, ShouldEqual, true) + So(msg.Align, ShouldEqual, "left") + }) + }) + }) +} diff --git a/test/widget_test.go b/test/widget_test.go new file mode 100644 index 0000000..dc523d5 --- /dev/null +++ b/test/widget_test.go @@ -0,0 +1,56 @@ +package i3status_test + +import ( + "github.com/ghedamat/go-i3status/i3status" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +func TestWidgetConstructor(t *testing.T) { + Convey("Given a widget", t, func() { + Convey("When it is created", func() { + Convey("a channel for incoming events is returned", func() { + So("", ShouldEqual, "implement me") + }) + }) + }) + + Convey("Given a Message channel", t, func() { + c := make(chan i3status.Message) + Convey("When a widget is created and a channel is passed", func() { + widget := i3status.NewWidget(c) + Convey("the widget has an output Message channel", func() { + So(widget.Output, ShouldEqual, c) + }) + Convey("the widget has an instance identifier", func() { + So(widget.Instance, ShouldNotEqual, 0) + }) + }) + }) + + Convey("Given two Widgets", t, func() { + c := make(chan i3status.Message) + w1 := i3status.NewWidget(c) + w2 := i3status.NewWidget(c) + Convey("When they are created", func() { + Convey("they have different instance identifiers", func() { + So(w1.Instance, ShouldNotEqual, w2.Instance) + }) + }) + }) + +} + +func TestWidgetSendMessage(t *testing.T) { + Convey("Given a Widget", t, func() { + c := make(chan i3status.Message) + widget := i3status.NewWidget(c) + Convey("When a widget is started", func() { + widget.Start() + Convey("it sends a Message to the channel", func() { + msg := <-c + So(msg.FullText, ShouldEqual, "Basic Widget") + }) + }) + }) +}