add hyprland sync-xkb-layout subcommand

parent 96127f2d
package config
import (
"log"
"github.com/godbus/dbus/v5"
)
var DBusConn *dbus.Conn
func InitDBus() {
var err error
DBusConn, err = dbus.SystemBus()
if err != nil {
log.Fatalf("failed to connect to system bus: %v", err)
}
}
......@@ -18,6 +18,7 @@ function __fish_ximperconf_complete
end
end
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var; and __fish_seen_subcommand_from set' -f -a '(__fish_ximperconf_complete)'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var; and __fish_seen_subcommand_from get' -f -a '(__fish_ximperconf_complete)'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var; and __fish_seen_subcommand_from unset' -f -a '(__fish_ximperconf_complete)'
......@@ -39,9 +40,12 @@ complete -x -c ximperconf -n '__fish_seen_subcommand_from repo; and __fish_seen_
complete -c ximperconf -n '__fish_seen_subcommand_from repo; and __fish_seen_subcommand_from deferred; and __fish_seen_subcommand_from last-update' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_ximperconf_no_subcommand' -a 'hyprland' -d 'Hyprland Management'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check module var' -a 'check' -d 'Check the Hyprland config'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check sync-xkb-layouts module var' -a 'check' -d 'Check the Hyprland config'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from check' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check module var' -a 'module' -d 'Hyprland modules'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check sync-xkb-layouts module var' -a 'sync-xkb-layouts' -d 'Sync layouts with xkb'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from sync-xkb-layouts' -f -l force -s f -d 'Forced update'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from sync-xkb-layouts' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check sync-xkb-layouts module var' -a 'module' -d 'Hyprland modules'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module' -f -l user -s u -d 'use user modules'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module; and not __fish_seen_subcommand_from status info enable disable toggle' -a 'status' -d 'Hyprland module status'
......@@ -55,7 +59,7 @@ complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_s
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module; and __fish_seen_subcommand_from disable' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module; and not __fish_seen_subcommand_from status info enable disable toggle' -a 'toggle' -d 'toggle module'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from module; and __fish_seen_subcommand_from toggle' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check module var' -a 'var' -d 'Hyprland vars'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and not __fish_seen_subcommand_from check sync-xkb-layouts module var' -a 'var' -d 'Hyprland vars'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var' -f -l help -s h -d 'show help'
complete -x -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var; and not __fish_seen_subcommand_from list info get set unset' -a 'list' -d 'vars list'
complete -c ximperconf -n '__fish_seen_subcommand_from hyprland; and __fish_seen_subcommand_from var; and __fish_seen_subcommand_from list' -f -l help -s h -d 'show help'
......
......@@ -4,6 +4,7 @@ go 1.25.0
require (
github.com/fatih/color v1.18.0
github.com/godbus/dbus/v5 v5.1.0
github.com/urfave/cli/v3 v3.4.1
)
......
......@@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
......
......@@ -20,6 +20,19 @@ func CommandList() *cli.Command {
Action: CheckHyprland,
},
{
Name: "sync-xkb-layouts",
Usage: "Sync layouts with xkb",
Action: HyprlandSyncSystemLayouts,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "force",
Usage: "Forced update",
Aliases: []string{"f"},
Value: false,
},
},
},
{
Name: "module",
Usage: "Hyprland modules",
Flags: []cli.Flag{
......
package hyprland
import (
"context"
"fmt"
"ximperconf/config"
"github.com/fatih/color"
"github.com/godbus/dbus/v5"
"github.com/urfave/cli/v3"
)
func hyprlandGetKeyboardLayouts() (string, error) {
obj := config.DBusConn.Object("org.freedesktop.locale1", "/org/freedesktop/locale1")
variant := dbus.Variant{}
err := obj.Call("org.freedesktop.DBus.Properties.Get", 0,
"org.freedesktop.locale1", "X11Layout").Store(&variant)
if err != nil {
return "", err
}
layoutStr, ok := variant.Value().(string)
if !ok {
return "", fmt.Errorf("unexpected type: %T", variant.Value())
}
return layoutStr, nil
}
func HyprlandSyncSystemLayouts(ctx context.Context, cmd *cli.Command) error {
force := cmd.Bool("force")
sysLayouts, err := hyprlandGetKeyboardLayouts()
if err != nil {
return fmt.Errorf("не удалось получить системные раскладки: %w", err)
}
hyprLayouts, err := hyprlandVarGet("kb_layout")
if err != nil {
return fmt.Errorf("не удалось получить kb_layout из Hyprland: %w", err)
}
if force || hyprLayouts == "" {
if _, err := hyprlandVarSet("kb_layout", sysLayouts); err != nil {
return fmt.Errorf("не удалось обновить kb_layout в Hyprland: %w", err)
}
color.Green("Раскладка обновлена!")
} else {
color.Red("Раскладка уже установлена, используйте '--force' для принудительного обновления.")
}
return nil
}
......@@ -119,19 +119,19 @@ func HyprlandVarInfoCommand(ctx context.Context, cmd *cli.Command) error {
func hyprlandVarGet(name string) (string, error) {
if name == "" {
color.Red("Укажите имя переменной")
os.Exit(1)
return "", fmt.Errorf("укажите имя переменной")
}
if !regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`).MatchString(name) {
color.Red("Недопустимое имя переменной: %s", name)
os.Exit(1)
return "", fmt.Errorf("недопустимое имя переменной: %s", name)
}
if !fileExists(config.Env.Hyprland.Config) {
color.Red("Конфигурация не найдена: %s", config.Env.Hyprland.Config)
os.Exit(1)
return "", fmt.Errorf("конфигурация не найдена: %s", config.Env.Hyprland.Config)
}
f, _ := os.Open(config.Env.Hyprland.Config)
f, err := os.Open(config.Env.Hyprland.Config)
if err != nil {
return "", err
}
defer f.Close()
sc := bufio.NewScanner(f)
......@@ -145,30 +145,30 @@ func hyprlandVarGet(name string) (string, error) {
return value, nil
}
}
color.Red("Переменная %s не найдена", name)
os.Exit(1)
return "", nil
return "", fmt.Errorf("переменная %s не найдена", name)
}
func HyprlandVarGetCommand(ctx context.Context, cmd *cli.Command) error {
info, _ := hyprlandVarGet(cmd.Args().Get(0))
info, err := hyprlandVarGet(cmd.Args().Get(0))
if err != nil {
color.Red(err.Error())
return err
}
fmt.Println(info)
return nil
}
func hyprlandVarSet(name, newValue string) error {
func hyprlandVarSet(name, newValue string) (string, error) {
if name == "" {
color.Red("Укажите имя переменной")
os.Exit(1)
return "", fmt.Errorf("укажите имя переменной")
}
if newValue == "" {
color.Red("Укажите новое значение")
os.Exit(1)
return "", fmt.Errorf("укажите новое значение")
}
if !regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`).MatchString(name) {
color.Red("Недопустимое имя переменной: %s", name)
os.Exit(1)
return "", fmt.Errorf("недопустимое имя переменной: %s", name)
}
path := config.Env.Hyprland.Config
......@@ -177,15 +177,21 @@ func hyprlandVarSet(name, newValue string) error {
_ = os.WriteFile(path, []byte{}, 0644)
}
data, _ := os.ReadFile(path)
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
lines := strings.Split(string(data), "\n")
changed := false
msg := ""
re := regexp.MustCompile(`^\s*\$` + regexp.QuoteMeta(name) + `\s*=`)
for i, l := range lines {
if re.MatchString(l) {
lines[i] = fmt.Sprintf("$%s = %s", name, newValue)
changed = true
msg = fmt.Sprintf("Переменная %s обновлена: %s", name, newValue)
}
}
......@@ -202,7 +208,7 @@ func hyprlandVarSet(name, newValue string) error {
before := append([]string{}, lines[:insertAt]...)
after := append([]string{fmt.Sprintf("$%s = %s", name, newValue)}, lines[insertAt:]...)
lines = append(before, after...)
color.Green("Переменная %s добавлена: %s", name, newValue)
msg = fmt.Sprintf("Переменная %s добавлена: %s", name, newValue)
} else {
// создаём блок VARS
lines = append(lines,
......@@ -210,18 +216,27 @@ func hyprlandVarSet(name, newValue string) error {
"#---------- ПЕРЕМЕННЫЕ ---- VARS",
fmt.Sprintf("$%s = %s", name, newValue),
)
color.Green("Блок VARS создан, переменная %s добавлена: %s", name, newValue)
msg = fmt.Sprintf("Блок VARS создан, переменная %s добавлена: %s", name, newValue)
}
} else {
color.Green("Переменная %s обновлена: %s", name, newValue)
}
return os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0644)
err = os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0644)
if err != nil {
return "", err
}
return msg, nil
}
func HyprlandVarSetCommand(ctx context.Context, cmd *cli.Command) error {
hyprlandVarSet(cmd.Args().Get(0), cmd.Args().Get(1))
msg, err := hyprlandVarSet(cmd.Args().Get(0), cmd.Args().Get(1))
if err != nil {
color.Red(err.Error())
return err
}
color.Green(msg)
return nil
}
......
......@@ -13,6 +13,8 @@ import (
func main() {
config.InitConfig()
config.InitDBus()
defer config.DBusConn.Close()
rootCommand := &cli.Command{
Name: "ximperconf",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment