hlctl/cmdlets/group/group.go

176 lines
4.0 KiB
Go

package group
import (
"errors"
"fmt"
"strconv"
"sectorinf.com/emilis/hlctl/cmdlets"
"sectorinf.com/emilis/hlctl/config"
"sectorinf.com/emilis/hlctl/ctllog"
"sectorinf.com/emilis/hlctl/groupctl"
"sectorinf.com/emilis/hlctl/hlcl"
"sectorinf.com/emilis/hlctl/notifyctl"
)
var log = ctllog.Logger{}.New("group", ctllog.ColorRGB{}.FromHex("27ee7e"))
type command struct{}
var Command command
func (command) Name() string {
return "group"
}
func (command) Usage() cmdlets.Usage {
return cmdlets.Usage{
Name: Command.Name(),
Short: "Controls tag grouping and behavior",
Long: []string{
"`group` is responsible for controlling how groups behave",
"in hlwm, and switching between them",
},
Flags: map[string]string{
"+": "Jump to next group",
"-": "Jump to previous group",
"[number]": "Jump to [number] group",
"move [number]": "Move the currently focused window to group [number]",
},
Examples: []string{
"hcctl group +",
"hcctl group -",
"hcctl group 2",
"hcctl group move 2",
},
}
}
func (command) Invoke(args ...string) error {
if len(args) == 0 {
return errors.New("group requires arguments")
}
arg := args[0]
if arg == "move" && len(args) < 2 {
return errors.New("group move requires an argument")
}
var active uint8
currentActiveCfg, err := config.Get(config.ActiveGroup)
if err != nil {
log.Warnf(
"error getting active group, defaulting to 1: %s",
err.Error(),
)
active = 1
} else {
val, err := currentActiveCfg.Uint()
mustUint(config.ActiveGroup, err)
active = uint8(val)
}
log.Print("Loading num of tags per group")
numCfg, err := config.Get(config.TagsPerGroup)
if err != nil {
return fmt.Errorf("%s: %w", config.TagsPerGroup, err)
}
num, err := numCfg.Uint()
mustUint(config.TagsPerGroup, err)
log.Print(num, "tags per group")
focus, err := config.GetFocusedTag()
if err != nil {
return fmt.Errorf("get focused tag: %w", err)
}
log.Print("Currently in", focus, "tag")
maxCfg, err := config.Get(config.GroupCount)
if err != nil {
return fmt.Errorf("%s: %w", config.GroupCount, err)
}
max, err := maxCfg.Uint()
mustUint(config.GroupCount, err)
var (
newActive uint8
)
switch arg {
case "+":
newActive = shiftGroup(false, active, uint8(max))
case "-":
newActive = shiftGroup(true, active, uint8(max))
case "move":
a, err := strconv.ParseUint(arg, 10, 8)
target := uint8(a)
if err != nil || target < 1 || target > max {
return fmt.Errorf("out of range, use [1:%d]", max)
}
return groupctl.MoveTo(uint8(a))
default:
a, err := strconv.ParseUint(arg, 10, 8)
target := uint8(a)
if err != nil || target < 1 || target > max {
return fmt.Errorf("out of range, use [1:%d]", max)
}
newActive = uint8(a)
}
if active != newActive {
log.Printf("Group %d -> %d", active, newActive)
config.Set(config.ActiveGroup, strconv.Itoa(int(newActive)))
// shift the tag index
if err := groupctl.Update(); err != nil {
return fmt.Errorf(
"updating groups [%d -> %d]: %w",
active,
newActive,
err,
)
}
}
if err := groupctl.SetKeybinds(newActive, uint8(num)); err != nil {
return fmt.Errorf("SetKeybinds: %w", err)
}
fg, _ := config.Get(config.ColorText)
bg, _ := config.Get(config.ColorNormal)
font, _ := config.Get(config.Font)
return notifyctl.Display(
fmt.Sprintf("Group %d", newActive),
2,
fg.String(),
bg.String(),
font.String(),
)
}
func moveTo(currentTag, currentGroup, newGroup, num uint8) error {
relTag := (currentTag - ((currentGroup - 1) * num))
newTag := ((newGroup - 1) * num) + relTag
return hlcl.MoveIndex(uint8(newTag))
}
func mustUint(cfg string, err error) {
if err != nil {
panic(fmt.Sprintf(
"%s must be set as uint: %s",
cfg,
err.Error(),
))
}
}
func shiftGroup(backwards bool, active, num uint8) uint8 {
// Maintain the logic of the fish scripts,
// 0 == 1, act as if groups are 1 indexed
if backwards && active <= 1 {
active = num
} else if backwards {
active--
} else if active >= num {
active = 1
} else {
active++
}
return uint8(active)
}