From 4e02e894e279152d78f8e2ac64f3e09f072ba003 Mon Sep 17 00:00:00 2001 From: Rodrigo Ipince Date: Wed, 22 Feb 2023 14:13:18 -0500 Subject: [PATCH 1/3] Add support for fish --- internal/nix/shell.go | 35 ++++++++++- internal/nix/shellrc_fish.tmpl | 109 +++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 internal/nix/shellrc_fish.tmpl diff --git a/internal/nix/shell.go b/internal/nix/shell.go index 748e5951a5d..bc1e8530201 100644 --- a/internal/nix/shell.go +++ b/internal/nix/shell.go @@ -25,6 +25,10 @@ import ( var shellrcText string var shellrcTmpl = template.Must(template.New("shellrc").Parse(shellrcText)) +//go:embed shellrc_fish.tmpl +var fishrcText string +var fishrcTmpl = template.Must(template.New("shellrc_fish").Parse(fishrcText)) + type name string const ( @@ -32,6 +36,7 @@ const ( shBash name = "bash" shZsh name = "zsh" shKsh name = "ksh" + shFish name = "fish" shPosix name = "posix" ) @@ -85,6 +90,9 @@ func DetectShell(opts ...ShellOption) (*Shell, error) { case "ksh": sh.name = shKsh sh.userShellrcPath = rcfilePath(".kshrc") + case "fish": + sh.name = shFish + sh.userShellrcPath = fishConfig() case "dash", "ash", "sh": sh.name = shPosix sh.userShellrcPath = os.Getenv("ENV") @@ -172,6 +180,19 @@ func rcfilePath(basename string) string { return filepath.Join(home, basename) } +func fishConfig() string { + xdg := os.Getenv("XDG_CONFIG_HOME") + if xdg != "" { + return filepath.Join(xdg, "fish", "config.fish") + } else { + home, err := os.UserHomeDir() + if err != nil { + return "" + } + return filepath.Join(home, ".config", "fish", "config.fish") + } +} + func (s *Shell) Run(nixShellFilePath, nixFlakesFilePath string) error { // Copy the current PATH into nix-shell, but clean and remove some // directories that are incompatible. @@ -342,6 +363,13 @@ func (s *Shell) shellRCOverrides(shellrc string) (extraEnv []string, extraArgs [ extraEnv = []string{fmt.Sprintf(`ZDOTDIR=%s`, shellescape.Quote(filepath.Dir(shellrc)))} case shKsh, shPosix: extraEnv = []string{fmt.Sprintf(`ENV=%s`, shellescape.Quote(shellrc))} + case shFish: + if featureflag.UnifiedEnv.Enabled() { + extraArgs = []string{"-C", ". " + shellrc} + } else { + // Needs quotes because it's wrapped inside the nix-shell command + extraArgs = []string{"-C", shellescape.Quote(". " + shellrc)} + } } return extraEnv, extraArgs } @@ -394,7 +422,12 @@ func (s *Shell) writeDevboxShellrc() (path string, err error) { pathPrepend = s.pkgConfigDir + ":" + pathPrepend } - err = shellrcTmpl.Execute(shellrcf, struct { + tmpl := shellrcTmpl + if s.name == shFish { + tmpl = fishrcTmpl + } + + err = tmpl.Execute(shellrcf, struct { ProjectDir string OriginalInit string OriginalInitPath string diff --git a/internal/nix/shellrc_fish.tmpl b/internal/nix/shellrc_fish.tmpl new file mode 100644 index 00000000000..b73cb21888c --- /dev/null +++ b/internal/nix/shellrc_fish.tmpl @@ -0,0 +1,109 @@ +{{- /* + +This template defines the shellrc file that the devbox shell will run at +startup when using the fish shell. + +It does _not_ include the user's original fish config, because unlike other +shells, fish has multiple files as part of its config, and it's difficult +to start a fish shell with a custom fish config. Instead, we let fish read +the user's original config directly, and run these commands next. + +Devbox needs to ensure that the shell's PATH, prompt, and a few other things are +set correctly after the user's shellrc runs. The commands to do this are in +the "Devbox Post-init Hook" section. + +This file is useful for debugging shell errors, so try to keep the generated +content readable. + +*/ -}} + +{{- if .UnifiedEnv -}} +# Run the shell hook defined in shell.nix or flake.nix +eval $shellHook + +{{ end -}} + +# Begin Devbox Post-init Hook + +{{- /* +NOTE: fish_add_path doesn't play nicely with colon:separated:paths, and I'd rather not +add string-splitting logic here nor parametrize computeNixEnv based on the shell being +used. So here we (ab)use the fact that using "export" ahead of the variable definition +makes fish do exactly what we want and behave in the same way as other shells. +*/ -}} +{{ if .UnifiedEnv -}} +export PATH="$DEVBOX_PATH_PREPEND:$PATH" +{{- else -}} +export PATH="{{ .PathPrepend }}:$PATH" +{{- end }} + +{{- /* +Set the history file by setting fish_history. This is not exactly the same as with other +shells, because we're not setting the file, but rather the session name, but it's a good +enough approximation for now. +*/ -}} +{{- if .HistoryFile }} +set fish_history devbox +{{- end }} + +# Prepend to the prompt to make it clear we're in a devbox shell. +functions -c fish_prompt __devbox_fish_prompt_orig +function fish_prompt + echo "(devbox)" (__devbox_fish_prompt_orig) +end + +{{- if .ShellStartTime }} +# log that the shell is ready now! +devbox log shell-ready {{ .ShellStartTime }} +{{ end }} + +# End Devbox Post-init Hook + +# Switch to the directory where devbox.json config is +set workingDir $(pwd) +cd {{ .ProjectDir }} + +{{- if .PluginInitHook }} + +# Begin Plugin Init Hook + +{{ .PluginInitHook }} + +# End Plugin Init Hook + +{{- end }} + +{{- if .UserHook }} + +# Begin Devbox User Hook + +{{ .UserHook }} + +# End Devbox User Hook + +{{- end }} + +cd $workingDir + +{{- if .ShellStartTime }} +# log that the shell is interactive now! +devbox log shell-interactive {{ .ShellStartTime }} +{{ end }} + +# Begin Script command + +{{- if .ScriptCommand }} + +function run_script + set workingDir $(pwd) + cd {{ .ProjectDir }} + + {{ .ScriptCommand }} + + cd $workingDir +end +{{- end }} + +# End Script command + +echo "finished" \ No newline at end of file From 2c6b248b7d030cab837444af9f18ee967e76e87d Mon Sep 17 00:00:00 2001 From: Rodrigo Ipince Date: Wed, 22 Feb 2023 14:27:36 -0500 Subject: [PATCH 2/3] remove debugging echo --- internal/nix/shellrc_fish.tmpl | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/nix/shellrc_fish.tmpl b/internal/nix/shellrc_fish.tmpl index b73cb21888c..febe6a14a72 100644 --- a/internal/nix/shellrc_fish.tmpl +++ b/internal/nix/shellrc_fish.tmpl @@ -105,5 +105,3 @@ end {{- end }} # End Script command - -echo "finished" \ No newline at end of file From 2ad9ccb94130e89feaed98ef540526a61a75160a Mon Sep 17 00:00:00 2001 From: Rodrigo Ipince Date: Thu, 23 Feb 2023 12:45:24 -0500 Subject: [PATCH 3/3] use xdg lib --- internal/nix/shell.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/internal/nix/shell.go b/internal/nix/shell.go index bc1e8530201..8c77903540f 100644 --- a/internal/nix/shell.go +++ b/internal/nix/shell.go @@ -19,6 +19,7 @@ import ( "go.jetpack.io/devbox/internal/boxcli/featureflag" "go.jetpack.io/devbox/internal/boxcli/usererr" "go.jetpack.io/devbox/internal/debug" + "go.jetpack.io/devbox/internal/xdg" ) //go:embed shellrc.tmpl @@ -181,16 +182,7 @@ func rcfilePath(basename string) string { } func fishConfig() string { - xdg := os.Getenv("XDG_CONFIG_HOME") - if xdg != "" { - return filepath.Join(xdg, "fish", "config.fish") - } else { - home, err := os.UserHomeDir() - if err != nil { - return "" - } - return filepath.Join(home, ".config", "fish", "config.fish") - } + return filepath.Join(xdg.ConfigDir(), "fish", "config.fish") } func (s *Shell) Run(nixShellFilePath, nixFlakesFilePath string) error {