From bd4b65256dd33ae6ab89f94021a09dad0563f36c Mon Sep 17 00:00:00 2001 From: milarin Date: Wed, 14 Feb 2024 17:21:50 +0100 Subject: [PATCH] comments and useful utils --- client.go | 16 +++++++++++++ get_bar_config.go | 2 ++ get_binding_modes.go | 1 + get_config.go | 2 ++ get_current_binding_mode.go | 1 + get_inputs.go | 1 + get_marks.go | 1 + get_outputs.go | 1 + get_seats.go | 1 + get_tree.go | 3 +++ get_version.go | 1 + get_workspaces.go | 1 + run_command.go | 4 ++++ send_tick.go | 1 + subscribe.go | 5 ++++ types.go | 47 +++++++++++++++++++++++++++++++++++++ utils.go | 5 ++++ 17 files changed, 93 insertions(+) create mode 100644 utils.go diff --git a/client.go b/client.go index 32a059d..d47a120 100644 --- a/client.go +++ b/client.go @@ -11,6 +11,17 @@ import ( "sync" ) +// Client is a single connection to a sway socket. +// All requests are synchronized in order to be thread-safe. +// That means they are processed in incoming order. +// If you want to be truly concurrent, use multiple clients +// connected to the same sway socket path. +// Subscriptions are the exception: They use their own socket connection +// so other requests are still possible. +// Subscription connections get closed as soon as the provided context is done. +// Use Client.Close after all requests are processed +// to close the connection to the socket. +// Client.Close does not handle subscriptions. type Client struct { sync.Mutex @@ -18,6 +29,8 @@ type Client struct { conn net.Conn } +// GetDefaultClient returns a sway client for the current seat. +// It determines the current seat by the SWAYSOCK environment variable func GetDefaultClient() (*Client, error) { socket, ok := os.LookupEnv("SWAYSOCK") if !ok { @@ -27,6 +40,7 @@ func GetDefaultClient() (*Client, error) { return GetClientBySocket(socket) } +// GetClientBySocket returns a sway client for the provided socket. func GetClientBySocket(socket string) (*Client, error) { conn, err := net.Dial("unix", socket) if err != nil { @@ -39,6 +53,8 @@ func GetClientBySocket(socket string) (*Client, error) { }, nil } +// Close closes the socket connection. +// All requests will return errors after calling Close func (c *Client) Close() error { c.Lock() defer c.Unlock() diff --git a/get_bar_config.go b/get_bar_config.go index c96ed78..1aab33d 100644 --- a/get_bar_config.go +++ b/get_bar_config.go @@ -1,9 +1,11 @@ package sway +// GetBarIDs returns a string array containing the IDs of all sway bars func (c *Client) GetBarIDs() ([]string, error) { return sendMessage[[]string](c, 6, "") } +// GetBarConfig returns the configuration for the given bar id func (c *Client) GetBarConfig(barID string) (*BarConfig, error) { return sendMessage[*BarConfig](c, 6, barID) } diff --git a/get_binding_modes.go b/get_binding_modes.go index 4acb3d1..cf7d90d 100644 --- a/get_binding_modes.go +++ b/get_binding_modes.go @@ -1,5 +1,6 @@ package sway +// GetBindingModes returns all binding modes configured in the config file func (c *Client) GetBindingModes() ([]string, error) { return sendMessage[[]string](c, 8, "") } diff --git a/get_config.go b/get_config.go index 522fe8d..30e8ae1 100644 --- a/get_config.go +++ b/get_config.go @@ -1,5 +1,7 @@ package sway +// GetConfig returns the content of the content file. +// Includes are not handled func (c *Client) GetConfig() (string, error) { cfg, err := sendMessage[config](c, 9, "") if err != nil { diff --git a/get_current_binding_mode.go b/get_current_binding_mode.go index 8d0bdc5..446275a 100644 --- a/get_current_binding_mode.go +++ b/get_current_binding_mode.go @@ -1,5 +1,6 @@ package sway +// GetCurrentBindingMode returns the currently active binding mode func (c *Client) GetCurrentBindingMode() (string, error) { mode, err := sendMessage[name](c, 12, "") if err != nil { diff --git a/get_inputs.go b/get_inputs.go index 1b35523..ea1afac 100644 --- a/get_inputs.go +++ b/get_inputs.go @@ -1,5 +1,6 @@ package sway +// GetInputs returns all input devices and their properties func (c *Client) GetInputs() ([]InputDevice, error) { return sendMessage[[]InputDevice](c, 100, "") } diff --git a/get_marks.go b/get_marks.go index 428d431..c48b4de 100644 --- a/get_marks.go +++ b/get_marks.go @@ -1,5 +1,6 @@ package sway +// GetMarks returns a string array containing all current marks func (c *Client) GetMarks() ([]string, error) { return sendMessage[[]string](c, 5, "") } diff --git a/get_outputs.go b/get_outputs.go index 232a369..385cf7d 100644 --- a/get_outputs.go +++ b/get_outputs.go @@ -1,5 +1,6 @@ package sway +// GetOutputs returns all outputs and their properties func (c *Client) GetOutputs() ([]Output, error) { return sendMessage[[]Output](c, 3, "") } diff --git a/get_seats.go b/get_seats.go index 041aa13..f6d152f 100644 --- a/get_seats.go +++ b/get_seats.go @@ -1,5 +1,6 @@ package sway +// GetSeats returns all sway seats func (c *Client) GetSeats() ([]Seat, error) { return sendMessage[[]Seat](c, 101, "") } diff --git a/get_tree.go b/get_tree.go index 01c591d..fddbe1b 100644 --- a/get_tree.go +++ b/get_tree.go @@ -1,5 +1,8 @@ package sway +// GetTree returns a Node object containing all +// outputs, workspaces, containers and windows in a recursive tree. +// Use Node.Find and Node.FindAll to search the tree recursively func (c *Client) GetTree() (*Node, error) { return sendMessage[*Node](c, 4, "") } diff --git a/get_version.go b/get_version.go index 13bf766..2c0633f 100644 --- a/get_version.go +++ b/get_version.go @@ -1,5 +1,6 @@ package sway +// GetVersion returns information about the sway version func (c *Client) GetVersion() (*Version, error) { return sendMessage[*Version](c, 7, "") } diff --git a/get_workspaces.go b/get_workspaces.go index 57ecebc..417c825 100644 --- a/get_workspaces.go +++ b/get_workspaces.go @@ -1,5 +1,6 @@ package sway +// GetWorkspaces returns all currently opened workspaces func (c *Client) GetWorkspaces() ([]Workspace, error) { return sendMessage[[]Workspace](c, 1, "") } diff --git a/run_command.go b/run_command.go index b9bba79..9956fc0 100644 --- a/run_command.go +++ b/run_command.go @@ -4,6 +4,10 @@ import ( "git.milar.in/milarin/slices" ) +// RunCommand runs all provided commands. +// It will return an array of errors +// which represent the result of each command. +// The last error is for communication problems only. func (c *Client) RunCommand(cmd string) ([]error, error) { results, err := sendMessage[[]commandResult](c, 0, cmd) if err != nil { diff --git a/send_tick.go b/send_tick.go index 6259375..5963566 100644 --- a/send_tick.go +++ b/send_tick.go @@ -1,5 +1,6 @@ package sway +// SendTick sends a tick with the given payload func (c *Client) SendTick(payload string) error { result, err := sendMessage[commandResult](c, 10, payload) if err != nil { diff --git a/subscribe.go b/subscribe.go index 4d31478..4b45147 100644 --- a/subscribe.go +++ b/subscribe.go @@ -11,6 +11,11 @@ import ( "git.milar.in/milarin/slices" ) +// Subscribe subscribes to the given event types +// and returns a channel in which all events get written into. +// A new socket connection will be established +// so other requests can still be used during a subscription. +// The subscription connection will be closed as soon as ctx is closed. func (c *Client) Subscribe(ctx context.Context, events ...EventType) (<-chan Event, error) { conn, err := net.Dial("unix", c.socket) if err != nil { diff --git a/types.go b/types.go index 8583819..b35d9cd 100644 --- a/types.go +++ b/types.go @@ -131,6 +131,53 @@ func (n Node) String() string { return string(data) } +// Find recursively searches n and returns the node +// for which condition returned true. +// condition is called in depth-first order: +// 1. for n +// 2. for n.Nodes (in order) +// 3. for n.FloatingNodes (in order) +// +// If no matching node is found, Find returns nil +func (n *Node) Find(condition func(n *Node) bool) *Node { + if condition(n) { + return n + } + + for _, child := range n.Nodes { + if node := child.Find(condition); node != nil { + return node + } + } + + for _, child := range n.FloatingNodes { + if node := child.Find(condition); node != nil { + return node + } + } + + return nil +} + +// FindAll behaves like Find but returns all matching nodes +func (n *Node) FindAll(condition func(n *Node) bool) []*Node { + nodes := []*Node{} + + if condition(n) { + nodes = append(nodes, n) + } + + for _, child := range n.Nodes { + nodes = append(nodes, child.FindAll(condition)...) + } + + for _, child := range n.FloatingNodes { + nodes = append(nodes, child.FindAll(condition)...) + } + + return nodes +} + type NodeType = string const ( diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..389a8fc --- /dev/null +++ b/utils.go @@ -0,0 +1,5 @@ +package sway + +func FindNodeByType(nodeType NodeType) func(n *Node) bool { + return func(n *Node) bool { return n.Type == nodeType } +}