176 lines
4.0 KiB
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)
|
||
|
}
|