Documentation
¶
Overview ¶
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules provides the core module system for i3going-on. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Package modules implements all the modules. Copyright (C) 2022 Kevin Lyda <[email protected]>
Index ¶
- func ClearRegistry()
- func ExecuteModuleClick(ctx context.Context, module ModuleV2, click Click) error
- func GetRegisteredTypes() []string
- func HandleClickEvent(ctx context.Context, modules []ModuleV2, click Click) error
- func IsRegistered(moduleType string) bool
- func ParseConfigBool(config map[string]any, key string, defaultValue bool) bool
- func ParseConfigFloat(config map[string]any, key string, defaultValue float64) float64
- func ParseConfigInt(config map[string]any, key string, defaultValue int) int
- func ParseConfigString(config map[string]any, key, defaultValue string) string
- func Register(moduleType string, factory ModuleFactory)
- func StartAll(ctx context.Context, modules []ModuleV2) error
- func StopAll(modules []ModuleV2) error
- func Unregister(moduleType string)
- type Action
- type ActionFunc
- type ActionProvider
- type BaseModule
- type BatteryModuleConfig
- type BatteryModuleV2
- type Block
- type CPUModuleConfig
- type CPUModuleV2
- type ChainAction
- type Click
- type ColorRule
- type DateModuleConfig
- type DateModuleV2
- func (d *DateModuleV2) GetClickAction(click Click) (Action, error)
- func (d *DateModuleV2) HandleClick(ctx context.Context, click Click) error
- func (d *DateModuleV2) ID() string
- func (d *DateModuleV2) Render(ctx context.Context) (Block, error)
- func (d *DateModuleV2) SetBlinkChar(char string)
- func (d *DateModuleV2) SetFormat(format string)
- func (d *DateModuleV2) Type() string
- type DiskModuleConfig
- type DiskModuleV2
- type LoadModuleConfig
- type LoadModuleV2
- type M
- type MemoryModuleConfig
- type MemoryModuleV2
- type MicrophoneModuleConfig
- type MicrophoneModuleV2
- type ModuleEntry
- func (m *ModuleEntry) HandleClick(ctx context.Context, click Click) error
- func (m *ModuleEntry) ID() string
- func (m *ModuleEntry) Render(ctx context.Context) (Block, error)
- func (m *ModuleEntry) Start(ctx context.Context) error
- func (m *ModuleEntry) Stop() error
- func (m *ModuleEntry) UnmarshalYAML(node *yaml.Node) error
- type ModuleFactory
- type ModuleV2
- func Create(moduleType, id string, config map[string]any) (ModuleV2, error)
- func FindModuleByID(modules []ModuleV2, id string) ModuleV2
- func NewBatteryModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewCPUModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewDateModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewDiskModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewLoadModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewMemoryModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewMicrophoneModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewNetworkModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewScriptModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewTextModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- func NewVolumeModuleV2FromConfig(id string, config map[string]any) (ModuleV2, error)
- type NetworkModuleConfig
- type NetworkModuleV2
- type NoOpAction
- type NotifyAction
- type ParallelAction
- type Params
- type RefreshAction
- type ScriptModuleConfig
- type ScriptModuleV2
- type ShellAction
- type TextModuleConfig
- type TextModuleV2
- func (t *TextModuleV2) GetClickAction(click Click) (Action, error)
- func (t *TextModuleV2) HandleClick(ctx context.Context, click Click) error
- func (t *TextModuleV2) ID() string
- func (t *TextModuleV2) Render(ctx context.Context) (Block, error)
- func (t *TextModuleV2) SetColor(color string)
- func (t *TextModuleV2) SetText(text string)
- func (t *TextModuleV2) Type() string
- type VolumeModuleConfig
- type VolumeModuleV2
Examples ¶
- ActionFunc
- BatteryModuleV2
- BatteryModuleV2 (Customization)
- BatteryModuleV2 (Registry)
- BatteryModuleV2 (Skip)
- BatteryModuleV2 (Skip)
- BatteryModuleV2 (WithIcon)
- BatteryModuleV2 (WithIcon)
- Block (Skip)
- CPUModuleV2
- CPUModuleV2 (Customization)
- CPUModuleV2 (Registry)
- ChainAction
- Create
- DateModuleV2
- DateModuleV2 (Blinking)
- DateModuleV2 (Registry)
- DiskModuleV2
- DiskModuleV2 (Customization)
- DiskModuleV2 (Registry)
- ExecuteModuleClick
- GetRegisteredTypes
- LoadModuleV2
- LoadModuleV2 (Customization)
- LoadModuleV2 (Registry)
- MemoryModuleV2
- MemoryModuleV2 (Customization)
- MemoryModuleV2 (Registry)
- NetworkModuleV2
- NetworkModuleV2 (AutoDetection)
- NetworkModuleV2 (AutoEthernet)
- NetworkModuleV2 (AutoWireless)
- NetworkModuleV2 (Customization)
- NetworkModuleV2 (PortableConfig)
- NetworkModuleV2 (Registry)
- NotifyAction
- ParallelAction
- Register
- RenderAll
- ScriptModuleV2
- ScriptModuleV2 (ColorRules)
- ScriptModuleV2 (Registry)
- ShellAction
- TextModuleV2
- TextModuleV2 (Defaults)
- TextModuleV2 (Dynamic)
- TextModuleV2.GetClickAction
- VolumeModuleV2
- VolumeModuleV2 (Customization)
- VolumeModuleV2 (Registry)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClearRegistry ¶
func ClearRegistry()
ClearRegistry removes all registered module types. This is primarily useful for testing.
func ExecuteModuleClick ¶
ExecuteModuleClick is a helper that handles click execution for modules. It checks if the module implements ActionProvider and uses that if available, otherwise falls back to calling HandleClick directly.
Example ¶
ExampleExecuteModuleClick demonstrates the helper function.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
textMod := modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "test",
Text: "Test",
OnClick: "echo 'test'",
})
ctx := context.Background()
click := modules.Click{Name: "test", Button: 1}
// This automatically uses ActionProvider if available
err := modules.ExecuteModuleClick(ctx, textMod, click)
fmt.Printf("Executed: %v\n", err == nil)
}
Output: Executed: true
func GetRegisteredTypes ¶
func GetRegisteredTypes() []string
GetRegisteredTypes returns a slice of all registered module type names. This is useful for error messages, help text, and validation.
Example ¶
ExampleGetRegisteredTypes demonstrates listing available module types.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
types := modules.GetRegisteredTypes()
// The text-v2 module should be registered
found := false
for _, t := range types {
if t == "text-v2" {
found = true
break
}
}
fmt.Printf("text-v2 registered: %v\n", found)
}
Output: text-v2 registered: true
func HandleClickEvent ¶
HandleClickEvent routes a click event to the appropriate module. Returns an error if the module is not found or if handling fails.
func IsRegistered ¶
IsRegistered checks if a module type is registered.
func ParseConfigBool ¶
ParseConfigBool extracts a boolean value from the config map.
func ParseConfigFloat ¶
ParseConfigFloat extracts a float64 value from the config map.
func ParseConfigInt ¶
ParseConfigInt extracts an integer value from the config map.
func ParseConfigString ¶
ParseConfigValue is a helper function for extracting typed values from config maps. It handles type assertions and provides sensible defaults.
Example usage:
text := ParseConfigString(config, "text", "default text") color := ParseConfigString(config, "color", "")
func Register ¶
func Register(moduleType string, factory ModuleFactory)
Register registers a new module type with the given factory function. This should be called during package initialization (in init() functions).
Example usage:
func init() {
modules.Register("text", NewTextModuleFromConfig)
}
If a module type is registered multiple times, the last registration wins.
Example ¶
ExampleRegister demonstrates registering a custom module.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Define a simple custom module factory
customFactory := func(id string, config map[string]any) (modules.ModuleV2, error) {
text := modules.ParseConfigString(config, "message", "Custom module!")
return modules.NewTextModuleV2(modules.TextModuleConfig{
ID: id,
Text: text,
}), nil
}
// Register the custom module type
modules.Register("custom", customFactory)
// Now we can create instances of it
mod, _ := modules.Create("custom", "custom-1", map[string]any{
"message": "This is custom",
})
ctx := context.Background()
block, _ := mod.Render(ctx)
fmt.Printf("Custom module: %s\n", block.FullText)
// Clean up for other tests
modules.Unregister("custom")
}
Output: Custom module: This is custom
func StartAll ¶
StartAll starts all modules in the slice. If any module fails to start, an error is returned immediately and previously started modules are stopped.
func StopAll ¶
StopAll stops all modules in the slice. All modules are stopped even if some return errors. Returns the first error encountered, if any.
Types ¶
type Action ¶
type Action interface {
// Execute performs the action.
// The context can be used for cancellation and timeout.
// The click parameter provides context about what was clicked.
Execute(ctx context.Context, click Click) error
}
Action represents an action that can be executed in response to a click event. Actions are returned by modules' HandleClick methods and executed by the bar.
Using actions instead of direct execution provides: - Type safety (no raw shell commands) - Testability (can mock actions) - Composability (chain multiple actions) - In-process operations (refresh, state changes)
type ActionFunc ¶
ActionFunc is a function adapter that implements the Action interface. This allows using simple functions as actions without defining new types.
Example ¶
ExampleActionFunc demonstrates using a function as an action.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Create an action from a function
action := modules.ActionFunc(func(ctx context.Context, click modules.Click) error {
fmt.Printf("Clicked module: %s with button %d\n", click.Name, click.Button)
return nil
})
ctx := context.Background()
click := modules.Click{Name: "my-module", Button: 1}
action.Execute(ctx, click)
}
Output: Clicked module: my-module with button 1
type ActionProvider ¶
type ActionProvider interface {
// GetClickAction returns an Action to execute for the given click event.
// Returns nil if no action should be taken.
GetClickAction(click Click) (Action, error)
}
ActionProvider is an optional interface that modules can implement to use the action system instead of executing commands directly in HandleClick.
Modules implementing this interface return Action objects which can then be executed, tested, or composed by the bar.
Example:
func (m *MyModule) GetClickAction(click Click) (Action, error) {
return &ShellAction{Command: "echo clicked!"}, nil
}
type BaseModule ¶
type BaseModule struct{}
BaseModule provides a default implementation of lifecycle methods that can be embedded in module implementations to reduce boilerplate.
Example usage:
type MyModule struct {
BaseModule
id string
// ... other fields
}
func (m *MyModule) ID() string { return m.id }
func (m *MyModule) Type() string { return "mymodule" }
func (m *MyModule) Render(ctx context.Context) (Block, error) {
// ... implementation
}
func (*BaseModule) HandleClick ¶
func (b *BaseModule) HandleClick(ctx context.Context, click Click) error
HandleClick is a no-op default implementation. Modules that don't handle clicks can embed BaseModule and not implement this.
func (*BaseModule) Start ¶
func (b *BaseModule) Start(ctx context.Context) error
Start is a no-op default implementation.
type BatteryModuleConfig ¶
type BatteryModuleConfig struct {
// ID is the unique identifier for this module instance.
// If not specified, defaults to "battery".
ID string `yaml:"id"`
// Battery is the battery index (0 for first battery, 1 for second, etc.).
// Defaults to 0.
Battery int `yaml:"battery"`
// WarnCmd is a command to execute when battery is below 20% and discharging.
// Example: ["notify-send", "Low battery!"]
WarnCmd []string `yaml:"warncmd"`
// OnClick is a shell command to execute when the module is clicked.
OnClick string `yaml:"on-click"`
// Icon is an optional prefix to display before the battery status.
// Example: "🔋", "BAT:", etc.
Icon string `yaml:"icon"`
// Status labels (customize how battery states are displayed)
StatusEmpty string `yaml:"status-emp"`
StatusCharging string `yaml:"status-chr"`
StatusBattery string `yaml:"status-bat"`
StatusUnknown string `yaml:"status-unk"`
StatusFull string `yaml:"status-full"`
OnError string `yaml:"on-error"`
// Colors for different battery levels
ColorOK string `yaml:"color-ok"`
Color20 string `yaml:"color-20"`
Color10 string `yaml:"color-10"`
ColorError string `yaml:"color-error"`
}
BatteryModuleConfig holds configuration for creating a BatteryModuleV2.
type BatteryModuleV2 ¶
type BatteryModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
BatteryModuleV2 displays battery status with percentage, state, and time remaining. This is a reimplementation of BatteryMod using the new ModuleV2 interface.
Example ¶
ExampleBatteryModuleV2 demonstrates creating a battery module. Note: This example may not work on systems without a battery.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
battMod := modules.NewBatteryModuleV2(modules.BatteryModuleConfig{
ID: "my-battery",
Battery: 0,
})
fmt.Printf("ID: %s\n", battMod.ID())
fmt.Printf("Type: %s\n", battMod.Type())
}
Output: ID: my-battery Type: battery
Example (Customization) ¶
ExampleBatteryModuleV2_customization demonstrates customizing battery display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
battMod := modules.NewBatteryModuleV2(modules.BatteryModuleConfig{
ID: "custom-battery",
StatusCharging: "⚡",
StatusBattery: "🔋",
StatusFull: "✓",
ColorOK: "#00ff00",
Color20: "#ff9900",
Color10: "#ff0000",
})
fmt.Printf("ID: %s\n", battMod.ID())
}
Output: ID: custom-battery
Example (Registry) ¶
ExampleBatteryModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("battery-v2", "bat0", map[string]any{
"battery": 0,
"status-chr": "CHR",
"color-ok": "#00ff00",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: battery
Example (Skip) ¶
ExampleBatteryModuleV2_skip demonstrates how the battery module automatically hides itself when no battery is present.
// Create modules for a desktop system without a battery
modules := []ModuleV2{
NewTextModuleV2(TextModuleConfig{
ID: "label",
Text: "Desktop",
}),
NewBatteryModuleV2(BatteryModuleConfig{
ID: "battery",
Battery: 0, // Will skip if no battery present
}),
NewDateModuleV2(DateModuleConfig{
ID: "clock",
Format: "15:04:05",
}),
}
// When rendered, if no battery is present, only the text and date modules will appear
ctx := context.Background()
blocks := RenderAll(ctx, modules)
// On a desktop without a battery, we'll only get 2 blocks
// The battery module automatically skips itself
_ = blocks
Example (Skip) ¶
ExampleBatteryModuleV2_skip demonstrates the automatic skip feature. When no battery is present, the module automatically hides itself.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Create a setup with multiple modules including battery
mods := []modules.ModuleV2{
modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "label",
Text: "System:",
}),
modules.NewBatteryModuleV2(modules.BatteryModuleConfig{
ID: "battery",
Battery: 99, // Non-existent battery to demonstrate skip
}),
modules.NewDateModuleV2(modules.DateModuleConfig{
ID: "clock",
Format: "15:04",
}),
}
// Render all modules
ctx := context.Background()
blocks := modules.RenderAll(ctx, mods)
// We only get 2 blocks (label + clock)
// The battery module automatically skips itself when battery doesn't exist
fmt.Printf("Modules defined: 3\n")
fmt.Printf("Blocks rendered: %d\n", len(blocks))
}
Output: Modules defined: 3 Blocks rendered: 2
Example (WithIcon) ¶
ExampleBatteryModuleV2_withIcon demonstrates using the battery module with an icon.
// Create a battery module with a custom icon
battery := NewBatteryModuleV2(BatteryModuleConfig{
ID: "my-battery",
Icon: "⚡",
})
// If a battery is present, the icon will be prefixed to the status:
// ⚡BAT 75.0% 2h30m
_ = battery
Example (WithIcon) ¶
ExampleBatteryModuleV2_withIcon demonstrates the new icon feature. The icon is prepended to the battery status text.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
battMod := modules.NewBatteryModuleV2(modules.BatteryModuleConfig{
ID: "icon-battery",
Icon: "🔋",
StatusCharging: "CHR",
StatusBattery: "BAT",
})
fmt.Printf("ID: %s\n", battMod.ID())
// When rendered (if battery exists), output would be: "🔋BAT 75.0% 2h30m"
}
Output: ID: icon-battery
func NewBatteryModuleV2 ¶
func NewBatteryModuleV2(cfg BatteryModuleConfig) *BatteryModuleV2
NewBatteryModuleV2 creates a new battery module with the given configuration.
func (*BatteryModuleV2) GetClickAction ¶
func (b *BatteryModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked. This implements the ActionProvider interface.
func (*BatteryModuleV2) HandleClick ¶
func (b *BatteryModuleV2) HandleClick(ctx context.Context, click Click) error
HandleClick executes the configured shell command if one is set. This method is kept for backward compatibility. New code should use GetClickAction() instead.
func (*BatteryModuleV2) ID ¶
func (b *BatteryModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*BatteryModuleV2) Render ¶
func (b *BatteryModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current battery status as a status block. It reads battery information, calculates time remaining based on discharge rate, and applies color coding based on battery level.
func (*BatteryModuleV2) Type ¶
func (b *BatteryModuleV2) Type() string
Type returns the module type identifier.
type Block ¶
type Block struct {
Name string `json:"name"` // Unique identifier for click events
FullText string `json:"full_text"` // Main text to display
ShortText string `json:"short_text,omitempty"` // Optional short text when space is limited
Color string `json:"color,omitempty"` // Text color (hex format: #RRGGBB)
Urgent bool `json:"urgent,omitempty"` // Whether to highlight as urgent
Separator bool `json:"separator,omitempty"` // Whether to show separator after this block
// Skip indicates this block should not be rendered in the status bar.
// This is useful for modules that are conditionally displayed (e.g., battery
// module when no battery is present). This field is not part of the JSON output.
Skip bool `json:"-"`
}
Block represents a single status bar element in the i3bar protocol. This struct encapsulates all the fields that can be rendered in a status block.
Example (Skip) ¶
ExampleBlock_skip demonstrates the Skip field in Block.
// A module can signal it should not be rendered by setting Skip=true
block := Block{
Name: "conditional-module",
FullText: "This won't be shown",
Skip: true, // This block will be filtered out by RenderAll
}
// When this block is included in RenderAll output, it will be omitted
_ = block
func RenderAll ¶
RenderAll renders all modules and returns a slice of Blocks. This is useful for rendering the entire status bar at once.
If a module fails to render, an error block is returned in its place so that the status bar can continue to function.
Modules that return blocks with Skip=true are omitted from the result. This allows modules to conditionally hide themselves (e.g., battery module when no battery is present).
Example ¶
ExampleRenderAll demonstrates rendering multiple modules at once.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
ctx := context.Background()
// Create several text modules
mods := []modules.ModuleV2{
modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "text1",
Text: "First",
}),
modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "text2",
Text: "Second",
}),
modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "text3",
Text: "Third",
}),
}
// Render them all at once
blocks := modules.RenderAll(ctx, mods)
for i, block := range blocks {
fmt.Printf("Block %d: %s\n", i+1, block.FullText)
}
}
Output: Block 1: First Block 2: Second Block 3: Third
type CPUModuleConfig ¶
type CPUModuleConfig struct {
ID string `yaml:"id"`
Format string `yaml:"format"`
Icon string `yaml:"icon"`
ShowTemp bool `yaml:"show-temp"`
TempZone string `yaml:"temp-zone"`
WarnPercent int `yaml:"warn-percent"`
CriticalPercent int `yaml:"critical-percent"`
ColorOK string `yaml:"color-ok"`
ColorWarn string `yaml:"color-warn"`
ColorCritical string `yaml:"color-critical"`
OnClick string `yaml:"on-click"`
}
CPUModuleConfig holds configuration for creating a CPUModuleV2.
type CPUModuleV2 ¶
type CPUModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
CPUModuleV2 displays CPU usage and optionally temperature.
Example ¶
ExampleCPUModuleV2 demonstrates creating a CPU module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
cpuMod := modules.NewCPUModuleV2(modules.CPUModuleConfig{
ID: "my-cpu",
Format: "percent",
})
fmt.Printf("ID: %s\n", cpuMod.ID())
fmt.Printf("Type: %s\n", cpuMod.Type())
}
Output: ID: my-cpu Type: cpu
Example (Customization) ¶
ExampleCPUModuleV2_customization demonstrates customizing CPU display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
cpuMod := modules.NewCPUModuleV2(modules.CPUModuleConfig{
ID: "custom-cpu",
Format: "with-temp",
ShowTemp: true,
Icon: "CPU:",
WarnPercent: 60,
CriticalPercent: 80,
ColorOK: "#00ff00",
ColorWarn: "#ffaa00",
ColorCritical: "#ff0000",
})
fmt.Printf("ID: %s\n", cpuMod.ID())
}
Output: ID: custom-cpu
Example (Registry) ¶
ExampleCPUModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("cpu-v2", "processor", map[string]any{
"format": "percent",
"show-temp": true,
"warn-percent": 70,
"critical-percent": 90,
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: cpu
func NewCPUModuleV2 ¶
func NewCPUModuleV2(cfg CPUModuleConfig) *CPUModuleV2
NewCPUModuleV2 creates a new CPU module with the given configuration.
func (*CPUModuleV2) GetClickAction ¶
func (c *CPUModuleV2) GetClickAction(_ Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*CPUModuleV2) ID ¶
func (c *CPUModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*CPUModuleV2) Render ¶
func (c *CPUModuleV2) Render(_ context.Context) (Block, error)
Render returns the current CPU usage as a status block.
func (*CPUModuleV2) Type ¶
func (c *CPUModuleV2) Type() string
Type returns the module type identifier.
type ChainAction ¶
type ChainAction struct {
Actions []Action // Actions to execute in order
}
ChainAction executes multiple actions in sequence. If any action fails, execution stops and the error is returned.
Example ¶
ExampleChainAction demonstrates chaining multiple actions.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
action := &modules.ChainAction{
Actions: []modules.Action{
&modules.ShellAction{Command: "echo 'First'"},
&modules.ShellAction{Command: "echo 'Second'"},
&modules.ShellAction{Command: "echo 'Third'"},
},
}
fmt.Printf("Chain has %d actions\n", len(action.Actions))
}
Output: Chain has 3 actions
type Click ¶
type ColorRule ¶
ColorRule maps a regex pattern to a color.
type DateModuleConfig ¶
type DateModuleConfig struct {
// ID is the unique identifier for this module instance.
// If not specified, defaults to "date".
ID string `yaml:"id"`
// Format is the Go time format string (e.g., "15:04:05" or "2006-01-02 15:04").
// If not specified, defaults to "06/01/02 15:04".
// See https://golang.org/pkg/time/#Time.Format for format syntax.
Format string `yaml:"format"`
// BlinkChar is a character to blink on/off each render cycle.
// For example, set to ":" to make colons in "15:04:05" blink.
// Optional - if not specified, no blinking occurs.
BlinkChar string `yaml:"blink-char"`
// OnClick is a shell command to execute when the module is clicked.
// Optional - if not specified, clicks do nothing.
OnClick string `yaml:"on-click"`
}
DateModuleConfig holds configuration for creating a DateModuleV2.
type DateModuleV2 ¶
type DateModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
DateModuleV2 displays the current date and time with optional blinking. This is a reimplementation of DateMod using the new ModuleV2 interface.
Example ¶
ExampleDateModuleV2 demonstrates creating and using a date module.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
dateMod := modules.NewDateModuleV2(modules.DateModuleConfig{
ID: "my-date",
Format: "15:04:05", // Show time only
})
ctx := context.Background()
// Start and render
dateMod.Start(ctx)
defer dateMod.Stop()
block, _ := dateMod.Render(ctx)
fmt.Printf("ID: %s\n", block.Name)
fmt.Printf("Type: %s\n", dateMod.Type())
// Note: We can't check the actual time in the test, but we can verify structure
fmt.Printf("Has time: %t\n", len(block.FullText) > 0)
}
Output: ID: my-date Type: date Has time: true
Example (Blinking) ¶
ExampleDateModuleV2_blinking demonstrates the blinking feature.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
dateMod := modules.NewDateModuleV2(modules.DateModuleConfig{
ID: "blink-date",
Format: "15:04:05",
BlinkChar: ":", // Make colons blink
})
ctx := context.Background()
// First render - colons visible
block1, _ := dateMod.Render(ctx)
hasColons1 := len(block1.FullText) > 0 && (block1.FullText[2:3] == ":" || block1.FullText[2:3] == " ")
// Second render - colons invisible (replaced with spaces)
block2, _ := dateMod.Render(ctx)
hasColons2 := len(block2.FullText) > 0 && (block2.FullText[2:3] == ":" || block2.FullText[2:3] == " ")
fmt.Printf("Blinking works: %t\n", hasColons1 || hasColons2)
}
Output: Blinking works: true
Example (Registry) ¶
ExampleDateModuleV2_registry demonstrates creating via registry.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("date-v2", "my-date", map[string]any{
"format": "2006-01-02",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
ctx := context.Background()
block, _ := mod.Render(ctx)
fmt.Printf("Type: %s\n", mod.Type())
fmt.Printf("Has date: %t\n", len(block.FullText) > 0)
}
Output: Type: date Has date: true
func NewDateModuleV2 ¶
func NewDateModuleV2(cfg DateModuleConfig) *DateModuleV2
NewDateModuleV2 creates a new date module with the given configuration.
func (*DateModuleV2) GetClickAction ¶
func (d *DateModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked. This implements the ActionProvider interface.
func (*DateModuleV2) HandleClick ¶
func (d *DateModuleV2) HandleClick(ctx context.Context, click Click) error
HandleClick executes the configured shell command if one is set. This method is kept for backward compatibility. New code should use GetClickAction() instead.
func (*DateModuleV2) ID ¶
func (d *DateModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*DateModuleV2) Render ¶
func (d *DateModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current date/time as a status block. If blinkChar is configured, it will toggle the visibility of that character each time Render is called, creating a blinking effect.
func (*DateModuleV2) SetBlinkChar ¶
func (d *DateModuleV2) SetBlinkChar(char string)
SetBlinkChar updates the blinking character.
func (*DateModuleV2) SetFormat ¶
func (d *DateModuleV2) SetFormat(format string)
SetFormat updates the time format string. This demonstrates dynamic reconfiguration.
func (*DateModuleV2) Type ¶
func (d *DateModuleV2) Type() string
Type returns the module type identifier.
type DiskModuleConfig ¶
type DiskModuleConfig struct {
ID string `yaml:"id"`
Path string `yaml:"path"`
Format string `yaml:"format"`
Icon string `yaml:"icon"`
WarnPercent int `yaml:"warn-percent"`
CriticalPercent int `yaml:"critical-percent"`
ColorOK string `yaml:"color-ok"`
ColorWarn string `yaml:"color-warn"`
ColorCritical string `yaml:"color-critical"`
OnClick string `yaml:"on-click"`
}
DiskModuleConfig holds configuration for creating a DiskModuleV2.
type DiskModuleV2 ¶
type DiskModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
DiskModuleV2 displays disk space usage for a mounted partition.
Example ¶
ExampleDiskModuleV2 demonstrates creating a disk usage module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
diskMod := modules.NewDiskModuleV2(modules.DiskModuleConfig{
ID: "my-disk",
Path: "/",
Format: "both",
})
fmt.Printf("ID: %s\n", diskMod.ID())
fmt.Printf("Type: %s\n", diskMod.Type())
}
Output: ID: my-disk Type: disk
Example (Customization) ¶
ExampleDiskModuleV2_customization demonstrates customizing disk module display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
diskMod := modules.NewDiskModuleV2(modules.DiskModuleConfig{
ID: "custom-disk",
Path: "/home",
Format: "percent",
Icon: "🗄️",
WarnPercent: 75,
CriticalPercent: 85,
ColorOK: "#00ff00",
ColorWarn: "#ff9900",
ColorCritical: "#ff0000",
})
fmt.Printf("ID: %s\n", diskMod.ID())
}
Output: ID: custom-disk
Example (Registry) ¶
ExampleDiskModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("disk-v2", "root-disk", map[string]any{
"path": "/",
"format": "short",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: disk
func NewDiskModuleV2 ¶
func NewDiskModuleV2(cfg DiskModuleConfig) *DiskModuleV2
NewDiskModuleV2 creates a new disk module with the given configuration.
func (*DiskModuleV2) GetClickAction ¶
func (d *DiskModuleV2) GetClickAction(_ Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*DiskModuleV2) ID ¶
func (d *DiskModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*DiskModuleV2) Render ¶
func (d *DiskModuleV2) Render(_ context.Context) (Block, error)
Render returns the current disk usage as a status block.
func (*DiskModuleV2) Type ¶
func (d *DiskModuleV2) Type() string
Type returns the module type identifier.
type LoadModuleConfig ¶
type LoadModuleConfig struct {
ID string `yaml:"id"`
Format string `yaml:"format"`
Icon string `yaml:"icon"`
ColorOK string `yaml:"color-ok"`
ColorWarn string `yaml:"color-warn"`
ColorCritical string `yaml:"color-critical"`
WarnThreshold float64 `yaml:"warn-threshold"`
CriticalThreshold float64 `yaml:"critical-threshold"`
OnClick string `yaml:"on-click"`
}
LoadModuleConfig holds configuration for creating a LoadModuleV2.
type LoadModuleV2 ¶
type LoadModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
LoadModuleV2 displays system load averages.
Example ¶
ExampleLoadModuleV2 demonstrates creating a load module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
loadMod := modules.NewLoadModuleV2(modules.LoadModuleConfig{
ID: "my-load",
Format: "all",
})
fmt.Printf("ID: %s\n", loadMod.ID())
fmt.Printf("Type: %s\n", loadMod.Type())
}
Output: ID: my-load Type: load
Example (Customization) ¶
ExampleLoadModuleV2_customization demonstrates customizing load display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
loadMod := modules.NewLoadModuleV2(modules.LoadModuleConfig{
ID: "custom-load",
Format: "1min",
Icon: "CPU:",
WarnThreshold: 0.5,
CriticalThreshold: 0.8,
ColorOK: "#00ff00",
ColorWarn: "#ffaa00",
ColorCritical: "#ff0000",
})
fmt.Printf("ID: %s\n", loadMod.ID())
}
Output: ID: custom-load
Example (Registry) ¶
ExampleLoadModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("load-v2", "system-load", map[string]any{
"format": "1-5",
"warn-threshold": 0.7,
"critical-threshold": 0.9,
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: load
func NewLoadModuleV2 ¶
func NewLoadModuleV2(cfg LoadModuleConfig) *LoadModuleV2
NewLoadModuleV2 creates a new load module with the given configuration.
func (*LoadModuleV2) GetClickAction ¶
func (l *LoadModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*LoadModuleV2) ID ¶
func (l *LoadModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*LoadModuleV2) Render ¶
func (l *LoadModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current system load as a status block.
func (*LoadModuleV2) Type ¶
func (l *LoadModuleV2) Type() string
Type returns the module type identifier.
type MemoryModuleConfig ¶
type MemoryModuleConfig struct {
ID string `yaml:"id"`
Format string `yaml:"format"`
Icon string `yaml:"icon"`
WarnPercent int `yaml:"warn-percent"`
CriticalPercent int `yaml:"critical-percent"`
ColorOK string `yaml:"color-ok"`
ColorWarn string `yaml:"color-warn"`
ColorCritical string `yaml:"color-critical"`
OnClick string `yaml:"on-click"`
}
MemoryModuleConfig holds configuration for creating a MemoryModuleV2.
type MemoryModuleV2 ¶
type MemoryModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
MemoryModuleV2 displays system memory usage.
Example ¶
ExampleMemoryModuleV2 demonstrates creating a memory module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
memMod := modules.NewMemoryModuleV2(modules.MemoryModuleConfig{
ID: "my-memory",
Format: "both",
})
fmt.Printf("ID: %s\n", memMod.ID())
fmt.Printf("Type: %s\n", memMod.Type())
}
Output: ID: my-memory Type: memory
Example (Customization) ¶
ExampleMemoryModuleV2_customization demonstrates customizing memory display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
memMod := modules.NewMemoryModuleV2(modules.MemoryModuleConfig{
ID: "custom-memory",
Format: "percent",
Icon: "RAM:",
WarnPercent: 70,
CriticalPercent: 85,
ColorOK: "#00ff00",
ColorWarn: "#ffaa00",
ColorCritical: "#ff0000",
})
fmt.Printf("ID: %s\n", memMod.ID())
}
Output: ID: custom-memory
Example (Registry) ¶
ExampleMemoryModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("memory-v2", "ram", map[string]any{
"format": "short",
"warn-percent": 80,
"critical-percent": 90,
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: memory
func NewMemoryModuleV2 ¶
func NewMemoryModuleV2(cfg MemoryModuleConfig) *MemoryModuleV2
NewMemoryModuleV2 creates a new memory module with the given configuration.
func (*MemoryModuleV2) GetClickAction ¶
func (m *MemoryModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*MemoryModuleV2) ID ¶
func (m *MemoryModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*MemoryModuleV2) Render ¶
func (m *MemoryModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current memory usage as a status block.
func (*MemoryModuleV2) Type ¶
func (m *MemoryModuleV2) Type() string
Type returns the module type identifier.
type MicrophoneModuleConfig ¶
type MicrophoneModuleConfig struct {
ID string `yaml:"id"`
Source string `yaml:"source"`
Format string `yaml:"format"`
Step int `yaml:"step"`
IconMuted string `yaml:"icon-muted"`
Icon string `yaml:"icon"`
ColorMuted string `yaml:"color-muted"`
ColorNormal string `yaml:"color-normal"`
OnClick string `yaml:"on-click"`
OnRightClick string `yaml:"on-right-click"`
}
MicrophoneModuleConfig holds configuration for creating a MicrophoneModuleV2.
type MicrophoneModuleV2 ¶
type MicrophoneModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
MicrophoneModuleV2 displays system volume level and mute status.
func NewMicrophoneModuleV2 ¶
func NewMicrophoneModuleV2(cfg MicrophoneModuleConfig) *MicrophoneModuleV2
NewMicrophoneModuleV2 creates a new volume module with the given configuration.
func (*MicrophoneModuleV2) GetClickAction ¶
func (v *MicrophoneModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*MicrophoneModuleV2) ID ¶
func (v *MicrophoneModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*MicrophoneModuleV2) Render ¶
func (v *MicrophoneModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current volume status as a status block.
func (*MicrophoneModuleV2) Type ¶
func (v *MicrophoneModuleV2) Type() string
Type returns the module type identifier.
type ModuleEntry ¶
type ModuleEntry struct {
Module string `yaml:"module"`
Name string `yaml:"name"`
OnClick string `yaml:"on-click"`
// contains filtered or unexported fields
}
ModuleEntry is the YAML configuration entry for a module. It handles parsing and creates the appropriate ModuleV2 implementation.
func NewErrorEntry ¶
func NewErrorEntry(name string, err error) ModuleEntry
NewErrorEntry creates a ModuleEntry that displays an error message.
func (*ModuleEntry) HandleClick ¶
func (m *ModuleEntry) HandleClick(ctx context.Context, click Click) error
HandleClick handles a click event on this module.
func (*ModuleEntry) ID ¶
func (m *ModuleEntry) ID() string
ID returns the module's unique identifier.
func (*ModuleEntry) Render ¶
func (m *ModuleEntry) Render(ctx context.Context) (Block, error)
Render returns the module's current state as a Block.
func (*ModuleEntry) Start ¶
func (m *ModuleEntry) Start(ctx context.Context) error
Start initializes the module.
func (*ModuleEntry) UnmarshalYAML ¶
func (m *ModuleEntry) UnmarshalYAML(node *yaml.Node) error
UnmarshalYAML parses the YAML config and creates the ModuleV2 implementation.
type ModuleFactory ¶
ModuleFactory is a function that creates a new ModuleV2 instance from configuration. The id parameter is the unique instance identifier for this module. The config parameter is a map of configuration values parsed from YAML.
Example factory function:
func NewTextModuleFromConfig(id string, config map[string]any) (ModuleV2, error) {
cfg := TextModuleConfig{ID: id}
// Parse config map into cfg struct...
return NewTextModuleV2(cfg), nil
}
type ModuleV2 ¶
type ModuleV2 interface {
// ID returns the unique instance identifier for this module.
// This is used for routing click events to the correct module instance.
// Example: "battery0", "date", "my-custom-text"
ID() string
// Type returns the module type identifier.
// This indicates what kind of module this is.
// Example: "battery", "date", "text", "network"
Type() string
// Start initializes the module and any resources it needs.
// This is called once when the module is created, before any Render calls.
// Use this to set up background goroutines, open files, etc.
//
// The context will be cancelled when the module should shut down.
// Long-running operations should respect context cancellation.
Start(ctx context.Context) error
// Stop cleans up any resources held by the module.
// This is called when the module is being removed or the program is exiting.
// Close files, stop goroutines, release memory, etc.
Stop() error
// Render generates the current status bar block for this module.
// This is called periodically (e.g., every 5 seconds) to update the display.
//
// The returned Block contains all the information needed to display
// this module in the status bar (text, color, etc.).
//
// Render should be fast and non-blocking. Heavy operations should be
// done in Start() or a background goroutine, with Render just returning
// the current cached state.
Render(ctx context.Context) (Block, error)
// HandleClick processes a click event for this module.
// This is called when the user clicks on this module's status bar entry.
//
// The Click parameter contains all information about the click:
// button number, modifiers, coordinates, etc.
//
// Return an error if the click cannot be handled.
HandleClick(ctx context.Context, click Click) error
}
ModuleV2 is the new, cleaner module interface that will eventually replace the Module struct + ParamsInterface pattern.
This interface provides: - Clear lifecycle management (Start/Stop) - Context support for cancellation and timeouts - Structured rendering with Block type instead of raw JSON strings - Per-module click handling instead of global routing
Modules can be migrated incrementally from the old ParamsInterface to this new interface without breaking existing functionality.
func Create ¶
Create creates a new module instance of the given type. The id parameter is the unique instance identifier. The config parameter is a map of configuration values.
Returns an error if: - The module type is not registered - The factory function returns an error
Example usage:
mod, err := modules.Create("text", "my-text", map[string]any{
"text": "Hello!",
"color": "#00ff00",
})
Example ¶
ExampleCreate demonstrates using the module registry to create modules.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Create a text module using the registry
mod, err := modules.Create("text-v2", "my-text", map[string]any{
"text": "Registry test",
"color": "#ff00ff",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// Use the module
ctx := context.Background()
block, _ := mod.Render(ctx)
fmt.Printf("Type: %s\n", mod.Type())
fmt.Printf("ID: %s\n", mod.ID())
fmt.Printf("Text: %s\n", block.FullText)
fmt.Printf("Color: %s\n", block.Color)
}
Output: Type: text ID: my-text Text: Registry test Color: #ff00ff
func FindModuleByID ¶
FindModuleByID searches for a module with the given ID. Returns nil if no module is found.
func NewBatteryModuleV2FromConfig ¶
NewBatteryModuleV2FromConfig is a factory function that creates a BatteryModuleV2 from a configuration map. This is used by the module registry.
func NewCPUModuleV2FromConfig ¶
NewCPUModuleV2FromConfig is a factory function that creates a CPUModuleV2 from a configuration map. This is used by the module registry.
func NewDateModuleV2FromConfig ¶
NewDateModuleV2FromConfig is a factory function that creates a DateModuleV2 from a configuration map. This is used by the module registry.
func NewDiskModuleV2FromConfig ¶
NewDiskModuleV2FromConfig is a factory function that creates a DiskModuleV2 from a configuration map. This is used by the module registry.
func NewLoadModuleV2FromConfig ¶
NewLoadModuleV2FromConfig is a factory function that creates a LoadModuleV2 from a configuration map. This is used by the module registry.
func NewMemoryModuleV2FromConfig ¶
NewMemoryModuleV2FromConfig is a factory function that creates a MemoryModuleV2 from a configuration map. This is used by the module registry.
func NewMicrophoneModuleV2FromConfig ¶
NewMicrophoneModuleV2FromConfig is a factory function that creates a MicrophoneModuleV2 from a configuration map. This is used by the module registry.
func NewNetworkModuleV2FromConfig ¶
NewNetworkModuleV2FromConfig is a factory function that creates a NetworkModuleV2 from a configuration map. This is used by the module registry.
func NewScriptModuleV2FromConfig ¶
NewScriptModuleV2FromConfig is a factory function that creates a ScriptModuleV2 from a configuration map. This is used by the module registry.
func NewTextModuleV2FromConfig ¶
NewTextModuleV2FromConfig is a factory function that creates a TextModuleV2 from a configuration map. This is used by the module registry.
type NetworkModuleConfig ¶
type NetworkModuleConfig struct {
ID string `yaml:"id"`
Interface string `yaml:"interface"`
ShowIP bool `yaml:"show-ip"`
ShowTraffic bool `yaml:"show-traffic"`
Format string `yaml:"format"`
IconConnected string `yaml:"icon-connected"`
IconDisconnected string `yaml:"icon-disconnected"`
ColorConnected string `yaml:"color-connected"`
ColorDisconnected string `yaml:"color-disconnected"`
OnClick string `yaml:"on-click"`
}
NetworkModuleConfig holds configuration for creating a NetworkModuleV2.
type NetworkModuleV2 ¶
type NetworkModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
NetworkModuleV2 displays network interface status and traffic.
Example ¶
ExampleNetworkModuleV2 demonstrates creating a network interface module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
netMod := modules.NewNetworkModuleV2(modules.NetworkModuleConfig{
ID: "my-network",
Interface: "eth0",
ShowIP: true,
ShowTraffic: true,
})
fmt.Printf("ID: %s\n", netMod.ID())
fmt.Printf("Type: %s\n", netMod.Type())
}
Output: ID: my-network Type: network
Example (AutoDetection) ¶
ExampleNetworkModuleV2_autoDetection demonstrates using auto-detection.
// Create a network module with auto-detection
// This will automatically find the first active network interface
netMod := NewNetworkModuleV2(NetworkModuleConfig{
ID: "auto-network",
Interface: "auto", // Auto-detect any interface
ShowIP: true,
ShowTraffic: true,
})
// Start the module to resolve the interface
ctx := context.Background()
netMod.Start(ctx)
// The module will now use whatever interface it detected
// Output depends on the system, so we just verify it was created
_ = netMod
Example (AutoEthernet) ¶
ExampleNetworkModuleV2_autoEthernet demonstrates ethernet auto-detection.
// Create a network module that auto-detects ethernet interfaces
// Perfect for desktop systems with wired connections
netMod := NewNetworkModuleV2(NetworkModuleConfig{
ID: "ethernet",
Interface: "auto-ethernet", // Auto-detect first ethernet interface
ShowIP: true,
ShowTraffic: true,
})
ctx := context.Background()
netMod.Start(ctx)
// Will find interfaces like: eth0, enp3s0, eno1, etc.
_ = netMod
Example (AutoWireless) ¶
ExampleNetworkModuleV2_autoWireless demonstrates wireless auto-detection.
// Create a network module that auto-detects wireless interfaces
// Perfect for laptops with WiFi
netMod := NewNetworkModuleV2(NetworkModuleConfig{
ID: "wifi",
Interface: "auto-wireless", // Auto-detect first wireless interface
ShowIP: true,
ShowTraffic: true,
})
ctx := context.Background()
netMod.Start(ctx)
// Will find interfaces like: wlan0, wlp2s0, wlo1, etc.
_ = netMod
Example (Customization) ¶
ExampleNetworkModuleV2_customization demonstrates customizing network module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
netMod := modules.NewNetworkModuleV2(modules.NetworkModuleConfig{
ID: "wifi",
Interface: "wlan0",
ShowIP: true,
ShowTraffic: true,
Format: "long",
IconConnected: "📶",
IconDisconnected: "❌",
ColorConnected: "#00ff00",
ColorDisconnected: "#ff0000",
})
fmt.Printf("ID: %s\n", netMod.ID())
}
Output: ID: wifi
Example (PortableConfig) ¶
ExampleNetworkModuleV2_portableConfig demonstrates a portable config.
// This configuration works across different machines without modification
// Each machine will auto-detect its own network interface
// For a laptop that might use ethernet OR wifi:
netMod1 := NewNetworkModuleV2(NetworkModuleConfig{
ID: "network",
Interface: "auto", // Uses whatever is active
})
// For a desktop that always uses ethernet:
netMod2 := NewNetworkModuleV2(NetworkModuleConfig{
ID: "network",
Interface: "auto-ethernet", // Only looks for wired
})
// For a mobile device that only has wifi:
netMod3 := NewNetworkModuleV2(NetworkModuleConfig{
ID: "network",
Interface: "auto-wireless", // Only looks for wireless
})
ctx := context.Background()
netMod1.Start(ctx)
netMod2.Start(ctx)
netMod3.Start(ctx)
// All three modules will work on their respective systems
_, _, _ = netMod1, netMod2, netMod3
Example (Registry) ¶
ExampleNetworkModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("network-v2", "eth", map[string]any{
"interface": "eth0",
"show-ip": true,
"show-traffic": true,
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: network
func NewNetworkModuleV2 ¶
func NewNetworkModuleV2(cfg NetworkModuleConfig) *NetworkModuleV2
NewNetworkModuleV2 creates a new network module with the given configuration.
func (*NetworkModuleV2) GetClickAction ¶
func (n *NetworkModuleV2) GetClickAction(_ Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*NetworkModuleV2) ID ¶
func (n *NetworkModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*NetworkModuleV2) Render ¶
func (n *NetworkModuleV2) Render(_ context.Context) (Block, error)
Render returns the current network status as a status block.
func (*NetworkModuleV2) Start ¶
func (n *NetworkModuleV2) Start(_ context.Context) error
Start resolves auto-detection interface names and initializes the module.
func (*NetworkModuleV2) Type ¶
func (n *NetworkModuleV2) Type() string
Type returns the module type identifier.
type NoOpAction ¶
type NoOpAction struct{}
NoOpAction does nothing. Useful as a placeholder or for testing.
type NotifyAction ¶
type NotifyAction struct {
Summary string // Title of the notification
Body string // Message body
Icon string // Optional icon name or path
}
NotifyAction shows a desktop notification using notify-send. This is useful for providing feedback without launching complex external programs.
Example ¶
ExampleNotifyAction demonstrates showing a desktop notification.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
action := &modules.NotifyAction{
Summary: "Test Notification",
Body: "This is a test",
Icon: "dialog-information",
}
// Note: This may not work in test environments without a display
fmt.Printf("Action type: %T\n", action)
}
Output: Action type: *modules.NotifyAction
type ParallelAction ¶
type ParallelAction struct {
Actions []Action // Actions to execute concurrently
}
ParallelAction executes multiple actions concurrently. All actions are started, and errors from any are collected and returned.
Example ¶
ExampleParallelAction demonstrates running actions concurrently.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
action := &modules.ParallelAction{
Actions: []modules.Action{
&modules.ShellAction{Command: "echo 'Action 1'"},
&modules.ShellAction{Command: "echo 'Action 2'"},
&modules.ShellAction{Command: "echo 'Action 3'"},
},
}
ctx := context.Background()
click := modules.Click{Name: "test", Button: 1}
err := action.Execute(ctx, click)
fmt.Printf("All executed: %v\n", err == nil)
}
Output: All executed: true
type Params ¶
Params is the structure for module specific params.
type RefreshAction ¶
type RefreshAction struct {
ModuleID string // ID of the module to refresh
}
RefreshAction triggers an immediate refresh of a specific module. This is useful when a click should update the display immediately rather than waiting for the next refresh cycle.
type ScriptModuleConfig ¶
type ScriptModuleConfig struct {
ID string `yaml:"id"`
Command string `yaml:"command"`
ColorRules []ColorRule `yaml:"color-rules"`
DefaultColor string `yaml:"default-color"`
OnError string `yaml:"on-error"`
OnClick string `yaml:"on-click"`
}
ScriptModuleConfig holds configuration for creating a ScriptModuleV2.
type ScriptModuleV2 ¶
type ScriptModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
ScriptModuleV2 executes a command and displays its output with conditional coloring.
Example ¶
ExampleScriptModuleV2 demonstrates creating a script module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
scriptMod := modules.NewScriptModuleV2(modules.ScriptModuleConfig{
ID: "my-script",
Command: "echo 'Hello from script'",
DefaultColor: "#00ff00",
})
fmt.Printf("ID: %s\n", scriptMod.ID())
fmt.Printf("Type: %s\n", scriptMod.Type())
}
Output: ID: my-script Type: script
Example (ColorRules) ¶
ExampleScriptModuleV2_colorRules demonstrates using color rules.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
scriptMod := modules.NewScriptModuleV2(modules.ScriptModuleConfig{
ID: "status-script",
Command: "echo 'OK: All systems go'",
ColorRules: []modules.ColorRule{
{Pattern: "^OK:", Color: "#00ff00"},
{Pattern: "^WARN:", Color: "#ffa500"},
{Pattern: "^ERROR:", Color: "#ff0000"},
},
DefaultColor: "#ffffff",
OnError: "Script failed",
})
fmt.Printf("ID: %s\n", scriptMod.ID())
fmt.Printf("Type: %s\n", scriptMod.Type())
}
Output: ID: status-script Type: script
Example (Registry) ¶
ExampleScriptModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("script-v2", "uptime", map[string]any{
"command": "uptime",
"default-color": "#00ff00",
"on-error": "Uptime unavailable",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: script
func NewScriptModuleV2 ¶
func NewScriptModuleV2(cfg ScriptModuleConfig) *ScriptModuleV2
NewScriptModuleV2 creates a new script module with the given configuration.
func (*ScriptModuleV2) GetClickAction ¶
func (s *ScriptModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*ScriptModuleV2) ID ¶
func (s *ScriptModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*ScriptModuleV2) Render ¶
func (s *ScriptModuleV2) Render(ctx context.Context) (Block, error)
Render executes the script and returns its output as a status block.
func (*ScriptModuleV2) Type ¶
func (s *ScriptModuleV2) Type() string
Type returns the module type identifier.
type ShellAction ¶
type ShellAction struct {
Command string // The shell command to execute
Env map[string]string // Optional environment variables
}
ShellAction executes a shell command. This is the most common action type for launching external programs.
Example ¶
ExampleShellAction demonstrates executing a shell command.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
action := &modules.ShellAction{
Command: "echo 'Hello from action!'",
}
ctx := context.Background()
click := modules.Click{Name: "test", Button: 1}
err := action.Execute(ctx, click)
fmt.Printf("Executed: %v\n", err == nil)
}
Output: Executed: true
type TextModuleConfig ¶
type TextModuleConfig struct {
// ID is the unique identifier for this module instance.
// If not specified, defaults to "text".
ID string `yaml:"id"`
// Text is the string to display in the status bar.
// If not specified, defaults to "Hello world!".
Text string `yaml:"text"`
// Color is the text color in hex format (#RRGGBB).
// If not specified, uses the default bar color.
Color string `yaml:"color"`
// OnClick is a shell command to execute when the module is clicked.
// Optional - if not specified, clicks do nothing.
OnClick string `yaml:"on-click"`
}
TextModuleConfig holds configuration for creating a TextModuleV2.
type TextModuleV2 ¶
type TextModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
TextModuleV2 is a reimplementation of TextMod using the new ModuleV2 interface. This serves as an example of how to write modules using the new interface.
The text module displays static text with optional color. It's the simplest module and serves as a good template for new modules.
Example ¶
ExampleTextModuleV2 demonstrates how to create and use the new TextModuleV2.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Create a new text module with custom configuration
textMod := modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "my-text",
Text: "Hello from V2!",
Color: "#00ff00",
OnClick: "echo 'clicked!'",
})
// Start the module (not required for text module, but good practice)
ctx := context.Background()
if err := textMod.Start(ctx); err != nil {
fmt.Printf("Error starting module: %v\n", err)
return
}
defer textMod.Stop()
// Render the module
block, err := textMod.Render(ctx)
if err != nil {
fmt.Printf("Error rendering: %v\n", err)
return
}
fmt.Printf("ID: %s\n", block.Name)
fmt.Printf("Text: %s\n", block.FullText)
fmt.Printf("Color: %s\n", block.Color)
}
Output: ID: my-text Text: Hello from V2! Color: #00ff00
Example (Defaults) ¶
ExampleTextModuleV2_defaults demonstrates using default values.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
// Create with minimal configuration - uses defaults
textMod := modules.NewTextModuleV2(modules.TextModuleConfig{})
ctx := context.Background()
block, _ := textMod.Render(ctx)
fmt.Printf("Default text: %s\n", block.FullText)
}
Output: Default text: Hello world!
Example (Dynamic) ¶
ExampleTextModuleV2_dynamic demonstrates updating module state.
package main
import (
"context"
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
textMod := modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "dynamic",
Text: "Initial text",
})
ctx := context.Background()
// Render initial state
block, _ := textMod.Render(ctx)
fmt.Printf("Before: %s\n", block.FullText)
// Update the text dynamically
textMod.SetText("Updated text")
// Render again
block, _ = textMod.Render(ctx)
fmt.Printf("After: %s\n", block.FullText)
}
Output: Before: Initial text After: Updated text
func NewTextModuleV2 ¶
func NewTextModuleV2(cfg TextModuleConfig) *TextModuleV2
NewTextModuleV2 creates a new text module with the given configuration.
func (*TextModuleV2) GetClickAction ¶
func (t *TextModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked. This implements the ActionProvider interface, which provides better testability and composability than HandleClick.
Example ¶
ExampleTextModuleV2_GetClickAction demonstrates the ActionProvider interface.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
textMod := modules.NewTextModuleV2(modules.TextModuleConfig{
ID: "clickable-text",
Text: "Click me!",
OnClick: "echo 'Clicked!'",
})
click := modules.Click{Name: "clickable-text", Button: 1}
// Get the action without executing it
action, err := textMod.GetClickAction(click)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Has action: %v\n", action != nil)
fmt.Printf("Action type: %T\n", action)
}
Output: Has action: true Action type: *modules.ShellAction
func (*TextModuleV2) HandleClick ¶
func (t *TextModuleV2) HandleClick(ctx context.Context, click Click) error
HandleClick executes the configured shell command if one is set. This method is kept for backward compatibility. New code should use GetClickAction() instead.
func (*TextModuleV2) ID ¶
func (t *TextModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*TextModuleV2) Render ¶
func (t *TextModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current status block for this module. For the text module, this is very simple - just return the configured text and color.
func (*TextModuleV2) SetColor ¶
func (t *TextModuleV2) SetColor(color string)
SetColor updates the text color.
func (*TextModuleV2) SetText ¶
func (t *TextModuleV2) SetText(text string)
SetText updates the displayed text. This demonstrates how modules can expose methods to update their state.
func (*TextModuleV2) Type ¶
func (t *TextModuleV2) Type() string
Type returns the module type identifier.
type VolumeModuleConfig ¶
type VolumeModuleConfig struct {
ID string `yaml:"id"`
Sink string `yaml:"sink"`
Format string `yaml:"format"`
Step int `yaml:"step"`
IconMuted string `yaml:"icon-muted"`
IconLow string `yaml:"icon-low"`
IconMedium string `yaml:"icon-medium"`
IconHigh string `yaml:"icon-high"`
ColorMuted string `yaml:"color-muted"`
ColorNormal string `yaml:"color-normal"`
OnClick string `yaml:"on-click"`
OnRightClick string `yaml:"on-right-click"`
}
VolumeModuleConfig holds configuration for creating a VolumeModuleV2.
type VolumeModuleV2 ¶
type VolumeModuleV2 struct {
BaseModule
// contains filtered or unexported fields
}
VolumeModuleV2 displays system volume level and mute status.
Example ¶
ExampleVolumeModuleV2 demonstrates creating a volume module.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
volMod := modules.NewVolumeModuleV2(modules.VolumeModuleConfig{
ID: "my-volume",
Format: "icon-percent",
})
fmt.Printf("ID: %s\n", volMod.ID())
fmt.Printf("Type: %s\n", volMod.Type())
}
Output: ID: my-volume Type: volume
Example (Customization) ¶
ExampleVolumeModuleV2_customization demonstrates customizing volume display.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
volMod := modules.NewVolumeModuleV2(modules.VolumeModuleConfig{
ID: "custom-volume",
Format: "icon-only",
IconMuted: "MUTE",
IconLow: "LOW",
IconMedium: "MED",
IconHigh: "HIGH",
ColorMuted: "#ff0000",
})
fmt.Printf("ID: %s\n", volMod.ID())
}
Output: ID: custom-volume
Example (Registry) ¶
ExampleVolumeModuleV2_registry demonstrates creating via registry.
package main
import (
"fmt"
"git.lyda.ie/kevin/i3going-on/modules"
)
func main() {
mod, err := modules.Create("volume-v2", "vol", map[string]any{
"format": "icon-percent",
"sink": "@DEFAULT_SINK@",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Type: %s\n", mod.Type())
}
Output: Type: volume
func NewVolumeModuleV2 ¶
func NewVolumeModuleV2(cfg VolumeModuleConfig) *VolumeModuleV2
NewVolumeModuleV2 creates a new volume module with the given configuration.
func (*VolumeModuleV2) GetClickAction ¶
func (v *VolumeModuleV2) GetClickAction(click Click) (Action, error)
GetClickAction returns an Action to execute when this module is clicked.
func (*VolumeModuleV2) ID ¶
func (v *VolumeModuleV2) ID() string
ID returns the unique identifier for this module instance.
func (*VolumeModuleV2) Render ¶
func (v *VolumeModuleV2) Render(ctx context.Context) (Block, error)
Render returns the current volume status as a status block.
func (*VolumeModuleV2) Type ¶
func (v *VolumeModuleV2) Type() string
Type returns the module type identifier.
Source Files
¶
- action.go
- battery_v2.go
- block.go
- clicks.go
- cpu_v2.go
- date_v2.go
- disk_v2.go
- helpers.go
- load_v2.go
- memory_v2.go
- microphone_v2.go
- module_v2.go
- modules.go
- network_v2.go
- registry.go
- script_v2.go
- text_v2.go
- volume_v2.go