summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/dbus.go37
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/exec.go44
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak.go83
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go271
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group.go37
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group_test.go142
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/gsettings.go31
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/math.go13
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths.go70
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths_test.go43
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices.go56
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices_test.go72
12 files changed, 899 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/dbus.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/dbus.go
new file mode 100644
index 0000000..bafd51f
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/dbus.go
@@ -0,0 +1,37 @@
+package utils
+
+import (
+ "slices"
+
+ "github.com/godbus/dbus/v5"
+)
+
+func IsDBusServiceAvailable(busName string) bool {
+ conn, err := dbus.ConnectSystemBus()
+ if err != nil {
+ return false
+ }
+ defer conn.Close()
+
+ obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
+ var owned bool
+ if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, busName).Store(&owned); err != nil {
+ return false
+ }
+ return owned
+}
+
+func IsDBusServiceActivatable(busName string) bool {
+ conn, err := dbus.ConnectSystemBus()
+ if err != nil {
+ return false
+ }
+ defer conn.Close()
+
+ obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
+ var activatable []string
+ if err := obj.Call("org.freedesktop.DBus.ListActivatableNames", 0).Store(&activatable); err != nil {
+ return false
+ }
+ return slices.Contains(activatable, busName)
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/exec.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/exec.go
new file mode 100644
index 0000000..aa1eb31
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/exec.go
@@ -0,0 +1,44 @@
+package utils
+
+import (
+ "os/exec"
+)
+
+type AppChecker interface {
+ CommandExists(cmd string) bool
+ AnyCommandExists(cmds ...string) bool
+ FlatpakExists(name string) bool
+ AnyFlatpakExists(flatpaks ...string) bool
+}
+
+type DefaultAppChecker struct{}
+
+func (DefaultAppChecker) CommandExists(cmd string) bool {
+ return CommandExists(cmd)
+}
+
+func (DefaultAppChecker) AnyCommandExists(cmds ...string) bool {
+ return AnyCommandExists(cmds...)
+}
+
+func (DefaultAppChecker) FlatpakExists(name string) bool {
+ return FlatpakExists(name)
+}
+
+func (DefaultAppChecker) AnyFlatpakExists(flatpaks ...string) bool {
+ return AnyFlatpakExists(flatpaks...)
+}
+
+func CommandExists(cmd string) bool {
+ _, err := exec.LookPath(cmd)
+ return err == nil
+}
+
+func AnyCommandExists(cmds ...string) bool {
+ for _, cmd := range cmds {
+ if CommandExists(cmd) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak.go
new file mode 100644
index 0000000..f1c9009
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak.go
@@ -0,0 +1,83 @@
+package utils
+
+import (
+ "bytes"
+ "errors"
+ "os/exec"
+ "slices"
+ "strings"
+)
+
+func FlatpakInPath() bool {
+ _, err := exec.LookPath("flatpak")
+ return err == nil
+}
+
+func FlatpakExists(name string) bool {
+ if !FlatpakInPath() {
+ return false
+ }
+
+ cmd := exec.Command("flatpak", "info", name)
+ err := cmd.Run()
+ return err == nil
+}
+
+func FlatpakSearchBySubstring(substring string) bool {
+ if !FlatpakInPath() {
+ return false
+ }
+
+ cmd := exec.Command("flatpak", "list", "--app")
+ var stdout bytes.Buffer
+ cmd.Stdout = &stdout
+
+ if err := cmd.Run(); err != nil {
+ return false
+ }
+
+ out := stdout.String()
+
+ for line := range strings.SplitSeq(out, "\n") {
+ fields := strings.Fields(line)
+ if len(fields) > 1 {
+ id := fields[1]
+ idParts := strings.Split(id, ".")
+ // We are assuming that the last part of the ID is
+ // the package name we're looking for. This might
+ // not always be true, some developers use arbitrary
+ // suffixes.
+ if len(idParts) > 0 && idParts[len(idParts)-1] == substring {
+ cmd := exec.Command("flatpak", "info", id)
+ err := cmd.Run()
+ return err == nil
+ }
+ }
+ }
+ return false
+}
+
+func AnyFlatpakExists(flatpaks ...string) bool {
+ return slices.ContainsFunc(flatpaks, FlatpakExists)
+}
+
+func FlatpakInstallationDir(name string) (string, error) {
+ if !FlatpakInPath() {
+ return "", errors.New("flatpak not found in PATH")
+ }
+
+ cmd := exec.Command("flatpak", "info", "--show-location", name)
+ var stdout bytes.Buffer
+ cmd.Stdout = &stdout
+
+ if err := cmd.Run(); err != nil {
+ return "", errors.New("flatpak not installed: " + name)
+ }
+
+ location := strings.TrimSpace(stdout.String())
+ if location == "" {
+ return "", errors.New("installation directory not found for: " + name)
+ }
+
+ return location, nil
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go
new file mode 100644
index 0000000..97282ae
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/flatpak_test.go
@@ -0,0 +1,271 @@
+package utils
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestFlatpakInPathAvailable(t *testing.T) {
+ result := FlatpakInPath()
+ if !result {
+ t.Skip("flatpak not in PATH")
+ }
+ if !result {
+ t.Errorf("expected true when flatpak is in PATH")
+ }
+}
+
+func TestFlatpakInPathUnavailable(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Setenv("PATH", tempDir)
+
+ result := FlatpakInPath()
+ if result {
+ t.Errorf("expected false when flatpak not in PATH, got true")
+ }
+}
+
+func TestFlatpakExistsValidPackage(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ result := FlatpakExists("com.nonexistent.package.test")
+ if result {
+ t.Logf("package exists (unexpected but not an error)")
+ }
+}
+
+func TestFlatpakExistsNoFlatpak(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Setenv("PATH", tempDir)
+
+ result := FlatpakExists("any.package.name")
+ if result {
+ t.Errorf("expected false when flatpak not in PATH, got true")
+ }
+}
+
+func TestFlatpakSearchBySubstringNoFlatpak(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Setenv("PATH", tempDir)
+
+ result := FlatpakSearchBySubstring("test")
+ if result {
+ t.Errorf("expected false when flatpak not in PATH, got true")
+ }
+}
+
+func TestFlatpakSearchBySubstringNonexistent(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ result := FlatpakSearchBySubstring("ThisIsAVeryUnlikelyPackageName12345")
+ if result {
+ t.Errorf("expected false for nonexistent package substring")
+ }
+}
+
+func TestFlatpakInstallationDirNoFlatpak(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Setenv("PATH", tempDir)
+
+ _, err := FlatpakInstallationDir("any.package.name")
+ if err == nil {
+ t.Errorf("expected error when flatpak not in PATH")
+ }
+ if err != nil && !strings.Contains(err.Error(), "not found in PATH") {
+ t.Errorf("expected 'not found in PATH' error, got: %v", err)
+ }
+}
+
+func TestFlatpakInstallationDirNonexistent(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ _, err := FlatpakInstallationDir("com.nonexistent.package.test")
+ if err == nil {
+ t.Errorf("expected error for nonexistent package")
+ }
+ if err != nil && !strings.Contains(err.Error(), "not installed") {
+ t.Errorf("expected 'not installed' error, got: %v", err)
+ }
+}
+
+func TestFlatpakInstallationDirValid(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ // This test requires a known installed flatpak
+ // We can't guarantee any specific flatpak is installed,
+ // so we'll skip if we can't find a common one
+ commonFlatpaks := []string{
+ "org.mozilla.firefox",
+ "org.gnome.Calculator",
+ "org.freedesktop.Platform",
+ }
+
+ var testPackage string
+ for _, pkg := range commonFlatpaks {
+ if FlatpakExists(pkg) {
+ testPackage = pkg
+ break
+ }
+ }
+
+ if testPackage == "" {
+ t.Skip("no common flatpak packages found for testing")
+ }
+
+ result, err := FlatpakInstallationDir(testPackage)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if result == "" {
+ t.Errorf("expected non-empty installation directory")
+ }
+ if !strings.Contains(result, testPackage) {
+ t.Logf("installation directory %s doesn't contain package name (may be expected)", result)
+ }
+}
+
+func TestFlatpakExistsCommandFailure(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ // Mock a failing flatpak command through PATH interception
+ tempDir := t.TempDir()
+ fakeFlatpak := filepath.Join(tempDir, "flatpak")
+
+ script := "#!/bin/sh\nexit 1\n"
+ err := os.WriteFile(fakeFlatpak, []byte(script), 0o755)
+ if err != nil {
+ t.Fatalf("failed to create fake flatpak: %v", err)
+ }
+
+ originalPath := os.Getenv("PATH")
+ t.Setenv("PATH", tempDir+":"+originalPath)
+
+ result := FlatpakExists("test.package")
+ if result {
+ t.Errorf("expected false when flatpak command fails, got true")
+ }
+}
+
+func TestFlatpakSearchBySubstringCommandFailure(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ // Mock a failing flatpak command through PATH interception
+ tempDir := t.TempDir()
+ fakeFlatpak := filepath.Join(tempDir, "flatpak")
+
+ script := "#!/bin/sh\nexit 1\n"
+ err := os.WriteFile(fakeFlatpak, []byte(script), 0o755)
+ if err != nil {
+ t.Fatalf("failed to create fake flatpak: %v", err)
+ }
+
+ originalPath := os.Getenv("PATH")
+ t.Setenv("PATH", tempDir+":"+originalPath)
+
+ result := FlatpakSearchBySubstring("test")
+ if result {
+ t.Errorf("expected false when flatpak command fails, got true")
+ }
+}
+
+func TestFlatpakInstallationDirCommandFailure(t *testing.T) {
+ if !FlatpakInPath() {
+ t.Skip("flatpak not in PATH")
+ }
+
+ // Mock a failing flatpak command through PATH interception
+ tempDir := t.TempDir()
+ fakeFlatpak := filepath.Join(tempDir, "flatpak")
+
+ script := "#!/bin/sh\nexit 1\n"
+ err := os.WriteFile(fakeFlatpak, []byte(script), 0o755)
+ if err != nil {
+ t.Fatalf("failed to create fake flatpak: %v", err)
+ }
+
+ originalPath := os.Getenv("PATH")
+ t.Setenv("PATH", tempDir+":"+originalPath)
+
+ _, err = FlatpakInstallationDir("test.package")
+ if err == nil {
+ t.Errorf("expected error when flatpak command fails")
+ }
+ if err != nil && !strings.Contains(err.Error(), "not installed") {
+ t.Errorf("expected 'not installed' error, got: %v", err)
+ }
+}
+
+func TestAnyFlatpakExistsSomeExist(t *testing.T) {
+ tempDir := t.TempDir()
+ fakeFlatpak := filepath.Join(tempDir, "flatpak")
+
+ // Script that succeeds only for "app.exists.test"
+ script := `#!/bin/sh
+if [ "$1" = "info" ] && [ "$2" = "app.exists.test" ]; then
+ exit 0
+fi
+exit 1
+`
+ err := os.WriteFile(fakeFlatpak, []byte(script), 0o755)
+ if err != nil {
+ t.Fatalf("failed to create fake flatpak: %v", err)
+ }
+
+ originalPath := os.Getenv("PATH")
+ t.Setenv("PATH", tempDir+":"+originalPath)
+
+ result := AnyFlatpakExists("com.nonexistent.flatpak", "app.exists.test", "com.another.nonexistent")
+ if !result {
+ t.Errorf("expected true when at least one flatpak exists")
+ }
+}
+
+func TestAnyFlatpakExistsNoneExist(t *testing.T) {
+ tempDir := t.TempDir()
+ fakeFlatpak := filepath.Join(tempDir, "flatpak")
+
+ script := "#!/bin/sh\nexit 1\n"
+ err := os.WriteFile(fakeFlatpak, []byte(script), 0o755)
+ if err != nil {
+ t.Fatalf("failed to create fake flatpak: %v", err)
+ }
+
+ originalPath := os.Getenv("PATH")
+ t.Setenv("PATH", tempDir+":"+originalPath)
+
+ result := AnyFlatpakExists("com.nonexistent.flatpak1", "com.nonexistent.flatpak2")
+ if result {
+ t.Errorf("expected false when no flatpaks exist")
+ }
+}
+
+func TestAnyFlatpakExistsNoFlatpak(t *testing.T) {
+ tempDir := t.TempDir()
+ t.Setenv("PATH", tempDir)
+
+ result := AnyFlatpakExists("any.package.name", "another.package")
+ if result {
+ t.Errorf("expected false when flatpak not in PATH, got true")
+ }
+}
+
+func TestAnyFlatpakExistsEmpty(t *testing.T) {
+ result := AnyFlatpakExists()
+ if result {
+ t.Errorf("expected false when no flatpaks specified")
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group.go
new file mode 100644
index 0000000..1a0a950
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group.go
@@ -0,0 +1,37 @@
+package utils
+
+import (
+ "os"
+ "strings"
+)
+
+func HasGroup(groupName string) bool {
+ return HasGroupIn(groupName, "/etc/group")
+}
+
+func HasGroupIn(groupName, path string) bool {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return false
+ }
+ return HasGroupData(groupName, string(data))
+}
+
+func HasGroupData(groupName, data string) bool {
+ prefix := groupName + ":"
+ for line := range strings.SplitSeq(data, "\n") {
+ if strings.HasPrefix(line, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+func FindGroupData(data string, candidates ...string) (string, bool) {
+ for _, candidate := range candidates {
+ if HasGroupData(candidate, data) {
+ return candidate, true
+ }
+ }
+ return "", false
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group_test.go
new file mode 100644
index 0000000..4b401dc
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/group_test.go
@@ -0,0 +1,142 @@
+package utils
+
+import "testing"
+
+const testGroupData = `root:x:0:brltty,root
+sys:x:3:bin,testuser
+mem:x:8:
+ftp:x:11:
+mail:x:12:
+log:x:19:
+smmsp:x:25:
+proc:x:26:
+games:x:50:
+lock:x:54:
+network:x:90:
+floppy:x:94:
+scanner:x:96:
+power:x:98:
+nobody:x:65534:
+adm:x:999:daemon
+wheel:x:998:testuser
+utmp:x:997:
+audio:x:996:brltty
+disk:x:995:
+input:x:994:brltty,testuser,greeter
+kmem:x:993:
+kvm:x:992:libvirt-qemu,qemu,testuser
+lp:x:991:cups,testuser
+optical:x:990:
+render:x:989:
+sgx:x:988:
+storage:x:987:
+tty:x:5:brltty
+uucp:x:986:brltty
+video:x:985:cosmic-greeter,greeter,testuser
+users:x:984:
+groups:x:983:
+systemd-journal:x:982:
+rfkill:x:981:
+bin:x:1:daemon
+daemon:x:2:bin
+http:x:33:
+dbus:x:81:
+systemd-coredump:x:980:
+systemd-network:x:979:
+systemd-oom:x:978:
+systemd-journal-remote:x:977:
+systemd-resolve:x:976:
+systemd-timesync:x:975:
+tss:x:974:
+uuidd:x:973:
+alpm:x:972:
+polkitd:x:102:
+testuser:x:1000:
+avahi:x:971:
+git:x:970:
+nvidia-persistenced:x:143:
+i2c:x:969:testuser
+seat:x:968:
+rtkit:x:133:
+brlapi:x:967:brltty
+gdm:x:120:
+brltty:x:966:
+colord:x:965:
+flatpak:x:964:
+geoclue:x:963:testuser
+gnome-remote-desktop:x:962:
+saned:x:961:
+usbmux:x:140:
+cosmic-greeter:x:960:
+greeter:x:959:testuser
+openvpn:x:958:
+nm-openvpn:x:957:
+named:x:40:
+_talkd:x:956:
+keyd:x:955:
+cups:x:209:testuser
+docker:x:954:testuser
+mysql:x:953:
+radicale:x:952:
+onepassword:x:1001:
+nixbld:x:951:nixbld01,nixbld02,nixbld03,nixbld04,nixbld05,nixbld06,nixbld07,nixbld08,nixbld09,nixbld10
+virtlogin:x:940:
+libvirt:x:939:testuser
+libvirt-qemu:x:938:
+qemu:x:937:
+dnsmasq:x:936:
+clock:x:935:
+dms-greeter:x:1002:greeter,testuser
+pcscd:x:934:
+test:x:1003:
+empower:x:933:
+`
+
+func TestHasGroupData(t *testing.T) {
+ tests := []struct {
+ group string
+ want bool
+ }{
+ {"greeter", true},
+ {"root", true},
+ {"docker", true},
+ {"cosmic-greeter", true},
+ {"dms-greeter", true},
+ {"nonexistent", false},
+ {"greet", false},
+ }
+
+ for _, tt := range tests {
+ if got := HasGroupData(tt.group, testGroupData); got != tt.want {
+ t.Errorf("HasGroupData(%q) = %v, want %v", tt.group, got, tt.want)
+ }
+ }
+}
+
+func TestFindGroupData(t *testing.T) {
+ tests := []struct {
+ name string
+ candidates []string
+ wantGroup string
+ wantFound bool
+ }{
+ {"first match wins", []string{"greeter", "greetd", "_greeter"}, "greeter", true},
+ {"fallback to second", []string{"greetd", "greeter"}, "greeter", true},
+ {"none found", []string{"_greetd", "greetd"}, "", false},
+ {"single match", []string{"docker"}, "docker", true},
+ }
+
+ for _, tt := range tests {
+ got, found := FindGroupData(testGroupData, tt.candidates...)
+ if got != tt.wantGroup || found != tt.wantFound {
+ t.Errorf("%s: FindGroupData(%v) = (%q, %v), want (%q, %v)",
+ tt.name, tt.candidates, got, found, tt.wantGroup, tt.wantFound)
+ }
+ }
+}
+
+func TestHasGroupDataEmpty(t *testing.T) {
+ if HasGroupData("greeter", "") {
+ t.Error("expected false for empty data")
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/gsettings.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/gsettings.go
new file mode 100644
index 0000000..cc8d084
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/gsettings.go
@@ -0,0 +1,31 @@
+package utils
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+)
+
+func dconfPath(schema, key string) string {
+ return "/" + strings.ReplaceAll(schema, ".", "/") + "/" + key
+}
+
+// GsettingsGet reads a gsettings value, falling back to dconf read.
+func GsettingsGet(schema, key string) (string, error) {
+ if out, err := exec.Command("gsettings", "get", schema, key).Output(); err == nil {
+ return strings.TrimSpace(string(out)), nil
+ }
+ out, err := exec.Command("dconf", "read", dconfPath(schema, key)).Output()
+ if err != nil {
+ return "", fmt.Errorf("gsettings/dconf get failed for %s %s: %w", schema, key, err)
+ }
+ return strings.TrimSpace(string(out)), nil
+}
+
+// GsettingsSet writes a gsettings value, falling back to dconf write.
+func GsettingsSet(schema, key, value string) error {
+ if err := exec.Command("gsettings", "set", schema, key, value).Run(); err == nil {
+ return nil
+ }
+ return exec.Command("dconf", "write", dconfPath(schema, key), "'"+value+"'").Run()
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/math.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/math.go
new file mode 100644
index 0000000..408af9f
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/math.go
@@ -0,0 +1,13 @@
+package utils
+
+import "golang.org/x/exp/constraints"
+
+func Clamp[T constraints.Ordered](val, min, max T) T {
+ if val < min {
+ return min
+ }
+ if val > max {
+ return max
+ }
+ return val
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths.go
new file mode 100644
index 0000000..053097e
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths.go
@@ -0,0 +1,70 @@
+package utils
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func XDGStateHome() string {
+ if dir := os.Getenv("XDG_STATE_HOME"); dir != "" {
+ return dir
+ }
+ home, _ := os.UserHomeDir()
+ return filepath.Join(home, ".local", "state")
+}
+
+func XDGDataHome() string {
+ if dir := os.Getenv("XDG_DATA_HOME"); dir != "" {
+ return dir
+ }
+ home, _ := os.UserHomeDir()
+ return filepath.Join(home, ".local", "share")
+}
+
+func XDGCacheHome() string {
+ if dir, err := os.UserCacheDir(); err == nil {
+ return dir
+ }
+ home, _ := os.UserHomeDir()
+ return filepath.Join(home, ".cache")
+}
+
+func XDGConfigHome() string {
+ if dir, err := os.UserConfigDir(); err == nil {
+ return dir
+ }
+ home, _ := os.UserHomeDir()
+ return filepath.Join(home, ".config")
+}
+
+func EmacsConfigDir() string {
+ home, _ := os.UserHomeDir()
+
+ emacsD := filepath.Join(home, ".emacs.d")
+ if info, err := os.Stat(emacsD); err == nil && info.IsDir() {
+ return emacsD
+ }
+
+ xdgEmacs := filepath.Join(XDGConfigHome(), "emacs")
+ if info, err := os.Stat(xdgEmacs); err == nil && info.IsDir() {
+ return xdgEmacs
+ }
+
+ return ""
+}
+
+func ExpandPath(path string) (string, error) {
+ expanded := os.ExpandEnv(path)
+ expanded = filepath.Clean(expanded)
+
+ if strings.HasPrefix(expanded, "~") {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ return "", err
+ }
+ expanded = filepath.Join(home, expanded[1:])
+ }
+
+ return expanded, nil
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths_test.go
new file mode 100644
index 0000000..964f2a7
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/paths_test.go
@@ -0,0 +1,43 @@
+package utils
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestExpandPathTilde(t *testing.T) {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ t.Skip("no home directory")
+ }
+ result, err := ExpandPath("~/test")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ expected := filepath.Join(home, "test")
+ if result != expected {
+ t.Errorf("expected %s, got %s", expected, result)
+ }
+}
+
+func TestExpandPathEnvVar(t *testing.T) {
+ t.Setenv("TEST_PATH_VAR", "/custom/path")
+ result, err := ExpandPath("$TEST_PATH_VAR/subdir")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if result != "/custom/path/subdir" {
+ t.Errorf("expected /custom/path/subdir, got %s", result)
+ }
+}
+
+func TestExpandPathAbsolute(t *testing.T) {
+ result, err := ExpandPath("/absolute/path")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if result != "/absolute/path" {
+ t.Errorf("expected /absolute/path, got %s", result)
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices.go
new file mode 100644
index 0000000..b636ddc
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices.go
@@ -0,0 +1,56 @@
+package utils
+
+func Filter[T any](items []T, predicate func(T) bool) []T {
+ var result []T
+ for _, item := range items {
+ if predicate(item) {
+ result = append(result, item)
+ }
+ }
+ return result
+}
+
+func Find[T any](items []T, predicate func(T) bool) (T, bool) {
+ for _, item := range items {
+ if predicate(item) {
+ return item, true
+ }
+ }
+ var zero T
+ return zero, false
+}
+
+func Map[T, U any](items []T, transform func(T) U) []U {
+ result := make([]U, len(items))
+ for i, item := range items {
+ result[i] = transform(item)
+ }
+ return result
+}
+
+func Contains[T comparable](items []T, target T) bool {
+ for _, item := range items {
+ if item == target {
+ return true
+ }
+ }
+ return false
+}
+
+func Any[T any](items []T, predicate func(T) bool) bool {
+ for _, item := range items {
+ if predicate(item) {
+ return true
+ }
+ }
+ return false
+}
+
+func All[T any](items []T, predicate func(T) bool) bool {
+ for _, item := range items {
+ if !predicate(item) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices_test.go
new file mode 100644
index 0000000..8edcee5
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/utils/slices_test.go
@@ -0,0 +1,72 @@
+package utils
+
+import (
+ "testing"
+)
+
+func TestFilter(t *testing.T) {
+ nums := []int{1, 2, 3, 4, 5}
+ evens := Filter(nums, func(n int) bool { return n%2 == 0 })
+ if len(evens) != 2 || evens[0] != 2 || evens[1] != 4 {
+ t.Errorf("expected [2, 4], got %v", evens)
+ }
+}
+
+func TestFilterEmpty(t *testing.T) {
+ result := Filter([]int{1, 2, 3}, func(n int) bool { return n > 10 })
+ if len(result) != 0 {
+ t.Errorf("expected empty slice, got %v", result)
+ }
+}
+
+func TestFind(t *testing.T) {
+ nums := []int{1, 2, 3, 4, 5}
+ val, found := Find(nums, func(n int) bool { return n == 3 })
+ if !found || val != 3 {
+ t.Errorf("expected 3, got %v (found=%v)", val, found)
+ }
+}
+
+func TestFindNotFound(t *testing.T) {
+ nums := []int{1, 2, 3}
+ val, found := Find(nums, func(n int) bool { return n == 99 })
+ if found || val != 0 {
+ t.Errorf("expected zero value not found, got %v (found=%v)", val, found)
+ }
+}
+
+func TestMap(t *testing.T) {
+ nums := []int{1, 2, 3}
+ doubled := Map(nums, func(n int) int { return n * 2 })
+ if len(doubled) != 3 || doubled[0] != 2 || doubled[1] != 4 || doubled[2] != 6 {
+ t.Errorf("expected [2, 4, 6], got %v", doubled)
+ }
+}
+
+func TestMapTypeConversion(t *testing.T) {
+ nums := []int{1, 2, 3}
+ strs := Map(nums, func(n int) string { return string(rune('a' + n - 1)) })
+ if strs[0] != "a" || strs[1] != "b" || strs[2] != "c" {
+ t.Errorf("expected [a, b, c], got %v", strs)
+ }
+}
+
+func TestContains(t *testing.T) {
+ nums := []int{1, 2, 3}
+ if !Contains(nums, 2) {
+ t.Error("expected to contain 2")
+ }
+ if Contains(nums, 99) {
+ t.Error("expected not to contain 99")
+ }
+}
+
+func TestAny(t *testing.T) {
+ nums := []int{1, 2, 3, 4, 5}
+ if !Any(nums, func(n int) bool { return n > 4 }) {
+ t.Error("expected any > 4")
+ }
+ if Any(nums, func(n int) bool { return n > 10 }) {
+ t.Error("expected none > 10")
+ }
+}