fix: ZDOTDIR and XDG_CONFIG_HOME config detecting (#51)

From this discussion:

https://www.reddit.com/r/zsh/comments/1v8rq7s/comment/p09b05o/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button

---

Problem: Iris hardcodes config paths to `~/.zshrc` and
`~/.config/fish/config.fish`. This ignores users' custom `ZDOTDIR` or
`XDG_CONFIG_HOME` setups, polluting their `$HOME` directory during init
and failing to scan their actual aliases. Also, ZDOTDIR is often set in
`~/.zshenv` without export, making it invisible to Go's `os.Getenv`

Solution:
- Bash: default `$HOME/.bashrc` so dont mind about it
- For Zsh, Iris now probes zsh directly (`zsh -c "echo $ZDOTDIR"`) with
a timeout to accurately resolve custom paths even if they aint exported
- For Fish, Iris now natively respects the `XDG_CONFIG_HOME` environment
variable
- Shared this robust resolution logic across init, uninstall, and alias
scanning
- Fixed alias scanning to process files in the correct zsh startup order
(`.zshenv` -> `.zprofile` -> `.zshrc`) and correctly merge them
This commit is contained in:
VERSE
2026-07-28 21:46:34 +07:00
committed by GitHub
parent 6f488c02cd
commit ebb0bead7d
3 changed files with 57 additions and 6 deletions
+49 -2
View File
@@ -1,11 +1,14 @@
package shell
import (
"context"
"fmt"
"maps"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
// Adapter defines the behavior for different shell environments
@@ -59,7 +62,43 @@ func (z *ZshAdapter) PrepareSelectSequence(selected string) []byte {
return append([]byte{0x15}, []byte(selected)...)
}
func (z *ZshAdapter) ScanAliases() map[string]string {
return ScanPosixAliases([]string{".zshrc", ".zshenv", ".zprofile"})
envSet := os.Getenv("ZDOTDIR") != ""
zdotdir := GetZshConfigDir()
home, _ := os.UserHomeDir()
var files []string
if !envSet && zdotdir != home {
files = append(files, filepath.Join(home, ".zshenv"))
}
files = append(files,
filepath.Join(zdotdir, ".zshenv"),
filepath.Join(zdotdir, ".zprofile"),
filepath.Join(zdotdir, ".zshrc"),
)
return ScanPosixAliases(files)
}
func GetZshConfigDir() string {
if zdotdir := os.Getenv("ZDOTDIR"); zdotdir != "" {
return zdotdir
}
// Fallback: ask zsh directly in case ZDOTDIR is set in ~/.zshenv without export
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
cmd := exec.CommandContext(ctx, "zsh", "-c", "echo $ZDOTDIR")
out, err := cmd.Output()
if err == nil {
zdotdir := strings.TrimSpace(string(out))
if zdotdir != "" {
return zdotdir
}
}
home, _ := os.UserHomeDir()
return home
}
// FishAdapter implementation
@@ -75,7 +114,15 @@ func (f *FishAdapter) PrepareSelectSequence(selected string) []byte {
}
func (f *FishAdapter) ScanAliases() map[string]string {
// fish uses 'alias' command in config.fish or separate function files
return ScanPosixAliases([]string{filepath.Join(".config", "fish", "config.fish")})
return ScanPosixAliases([]string{filepath.Join(GetFishConfigDir(), "config.fish")})
}
func GetFishConfigDir() string {
if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
return filepath.Join(xdg, "fish")
}
home, _ := os.UserHomeDir()
return filepath.Join(home, ".config", "fish")
}
func ScanPosixAliases(files []string) map[string]string {