// SPDX-License-Identifier: GPL-3.0-or-later // Package xdg resolves the XDG base directories and expands ~ in paths. package xdg import ( "os" "path/filepath" "strings" ) // ConfigHome is $XDG_CONFIG_HOME, or ~/.config. func ConfigHome() string { return base("XDG_CONFIG_HOME", ".config") } // StateHome is $XDG_STATE_HOME, or ~/.local/state. func StateHome() string { return base("XDG_STATE_HOME", filepath.Join(".local", "state")) } // DataHome is $XDG_DATA_HOME, or ~/.local/share. func DataHome() string { return base("XDG_DATA_HOME", filepath.Join(".local", "share")) } // base follows the XDG rule that a relative value is invalid and ignored. func base(env, fallback string) string { if v := os.Getenv(env); filepath.IsAbs(v) { return filepath.Clean(v) } return filepath.Join(Home(), fallback) } // Home is the user's home directory, or "/" when it is unknown. func Home() string { if h, err := os.UserHomeDir(); err == nil && h != "" { return filepath.Clean(h) } return "/" } // Expand replaces a leading "~" or "~/" with the home directory. // "~user" is left alone. func Expand(p string) string { if p == "~" { return Home() } if strings.HasPrefix(p, "~/") { return filepath.Join(Home(), p[2:]) } return p } // Abbrev replaces a leading home directory with "~", for display and for // paths written into config files. func Abbrev(p string) string { h := Home() if p == h { return "~" } if h != "/" && strings.HasPrefix(p, h+"/") { return "~/" + p[len(h)+1:] } return p }