Skip to content

Commit 965e05a

Browse files
authored
[shell] preserve history (#204)
## Summary This PR aims to preserve shell command history across sessions, where sessions is defined as starting and exiting a `devbox shell`. ## How was it tested? - started a `devbox shell` - invoked `go version` and `which go` and `exit` - restarted the `devbox shell` - used up arrow key to get the previous commands used.
1 parent ffe558f commit 965e05a

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

devbox.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ import (
2525
"golang.org/x/exp/slices"
2626
)
2727

28-
// profileDir contains the contents of the profile generated via `nix-env --profile profileDir <command>`
29-
const profileDir = ".devbox/profile"
28+
const (
29+
// configFilename is name of the JSON file that defines a devbox environment.
30+
configFilename = "devbox.json"
31+
32+
// profileDir contains the contents of the profile generated via `nix-env --profile profileDir <command>`
33+
profileDir = ".devbox/profile"
3034

31-
// configFilename is name of the JSON file that defines a devbox environment.
32-
const configFilename = "devbox.json"
35+
// shellHistoryFile keeps the history of commands invoked inside devbox shell
36+
shellHistoryFile = ".devbox/shell_history"
37+
)
3338

3439
// InitConfig creates a default devbox config file if one doesn't already
3540
// exist.
@@ -175,7 +180,11 @@ func (d *Devbox) Shell() error {
175180
return errors.WithStack(err)
176181
}
177182
nixShellFilePath := filepath.Join(d.srcDir, ".devbox/gen/shell.nix")
178-
sh, err := nix.DetectShell(nix.WithPlanInitHook(plan.ShellInitHook), nix.WithProfile(d.profileDir()))
183+
sh, err := nix.DetectShell(
184+
nix.WithPlanInitHook(plan.ShellInitHook),
185+
nix.WithProfile(d.profileDir()),
186+
nix.WithHistoryFile(filepath.Join(d.srcDir, shellHistoryFile)),
187+
)
179188
if err != nil {
180189
// Fall back to using a plain Nix shell.
181190
sh = &nix.Shell{}

nix/shell.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ type Shell struct {
4343
UserInitHook string
4444

4545
// profileDir is the absolute path to the directory storing the nix-profile
46-
profileDir string
46+
profileDir string
47+
historyFile string
4748
}
4849

4950
type ShellOption func(*Shell)
@@ -106,6 +107,12 @@ func WithProfile(profileDir string) ShellOption {
106107
}
107108
}
108109

110+
func WithHistoryFile(historyFile string) ShellOption {
111+
return func(s *Shell) {
112+
s.historyFile = historyFile
113+
}
114+
}
115+
109116
// rcfilePath returns the absolute path for an rcfile, which is usually in the
110117
// user's home directory. It doesn't guarantee that the file exists.
111118
func rcfilePath(basename string) string {
@@ -262,12 +269,14 @@ func (s *Shell) writeDevboxShellrc() (path string, err error) {
262269
UserHook string
263270
PlanInitHook string
264271
ProfileBinDir string
272+
HistoryFile string
265273
}{
266274
OriginalInit: string(bytes.TrimSpace(userShellrc)),
267275
OriginalInitPath: filepath.Clean(s.userShellrcPath),
268276
UserHook: strings.TrimSpace(s.UserInitHook),
269277
PlanInitHook: strings.TrimSpace(s.planInitHook),
270278
ProfileBinDir: s.profileDir + "/bin",
279+
HistoryFile: strings.TrimSpace(s.historyFile),
271280
})
272281
if err != nil {
273282
return "", fmt.Errorf("execute shellrc template: %v", err)

nix/shellrc.tmpl

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ PATH="$(
6464
echo "{{ .ProfileBinDir }}:${non_nix_path}"
6565
)"
6666

67+
{{- if .HistoryFile }}
68+
HISTFILE={{.HistoryFile}}
69+
{{- end }}
70+
6771
# Prepend to the prompt to make it clear we're in a devbox shell.
6872
export PS1="(devbox) $PS1"
6973

0 commit comments

Comments
 (0)