mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-14 02:57:52 +08:00
parent
212a21d051
commit
6938c8d117
|
@ -4,6 +4,7 @@ package shell
|
|||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/elves/elvish/pkg/cli/term"
|
||||
|
@ -17,6 +18,7 @@ var logger = util.GetLogger("[shell] ")
|
|||
func setupShell(fds [3]*os.File, p Paths, spawn bool) (*eval.Evaler, func()) {
|
||||
restoreTTY := term.SetupGlobal()
|
||||
ev := InitRuntime(fds[2], p, spawn)
|
||||
restoreSHLVL := incSHLVL()
|
||||
|
||||
sigs := make(chan os.Signal)
|
||||
signal.Notify(sigs)
|
||||
|
@ -29,6 +31,7 @@ func setupShell(fds [3]*os.File, p Paths, spawn bool) (*eval.Evaler, func()) {
|
|||
|
||||
return ev, func() {
|
||||
signal.Stop(sigs)
|
||||
restoreSHLVL()
|
||||
CleanupRuntime(fds[2], ev)
|
||||
restoreTTY()
|
||||
}
|
||||
|
@ -41,6 +44,28 @@ func evalInTTY(ev *eval.Evaler, op eval.Op, fds [3]*os.File) error {
|
|||
Ports: ports[:], Interrupt: eval.ListenInterrupts, PutInFg: true})
|
||||
}
|
||||
|
||||
const envSHLVL = "SHLVL"
|
||||
|
||||
func incSHLVL() func() {
|
||||
restoreSHLVL := saveEnv(envSHLVL)
|
||||
|
||||
i, err := strconv.Atoi(os.Getenv(envSHLVL))
|
||||
if err != nil {
|
||||
i = 0
|
||||
}
|
||||
os.Setenv(envSHLVL, strconv.Itoa(i+1))
|
||||
|
||||
return restoreSHLVL
|
||||
}
|
||||
|
||||
func saveEnv(name string) func() {
|
||||
v, ok := os.LookupEnv(name)
|
||||
if ok {
|
||||
return func() { os.Setenv(name, v) }
|
||||
}
|
||||
return func() { os.Unsetenv(name) }
|
||||
}
|
||||
|
||||
// Global panic handler.
|
||||
func rescue() {
|
||||
r := recover()
|
||||
|
|
68
pkg/program/shell/shell_test.go
Normal file
68
pkg/program/shell/shell_test.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShell_SHLVL_NormalCase(t *testing.T) {
|
||||
restore := saveEnv("SHLVL")
|
||||
defer restore()
|
||||
|
||||
os.Setenv("SHLVL", "10")
|
||||
testSHLVL(t, "11")
|
||||
}
|
||||
|
||||
func TestShell_SHLVL_Unset(t *testing.T) {
|
||||
restore := saveEnv("SHLVL")
|
||||
defer restore()
|
||||
|
||||
os.Unsetenv("SHLVL")
|
||||
testSHLVL(t, "1")
|
||||
}
|
||||
|
||||
func TestShell_SHLVL_Invalid(t *testing.T) {
|
||||
restore := saveEnv("SHLVL")
|
||||
defer restore()
|
||||
|
||||
os.Setenv("SHLVL", "invalid")
|
||||
testSHLVL(t, "1")
|
||||
}
|
||||
|
||||
func TestShell_NegativeSHLVL_Increments(t *testing.T) {
|
||||
// Other shells don't agree what the behavior should be:
|
||||
//
|
||||
// ~> E:SHLVL=-100 bash -c 'echo $SHLVL'
|
||||
// 0
|
||||
// ~> E:SHLVL=-100 zsh -c 'echo $SHLVL'
|
||||
// -99
|
||||
// ~> E:SHLVL=-100 fish -c 'echo $SHLVL'
|
||||
// 1
|
||||
//
|
||||
// Elvish follows Zsh here.
|
||||
restore := saveEnv("SHLVL")
|
||||
defer restore()
|
||||
|
||||
os.Setenv("SHLVL", "-100")
|
||||
testSHLVL(t, "-99")
|
||||
}
|
||||
|
||||
func testSHLVL(t *testing.T, wantSHLVL string) {
|
||||
t.Helper()
|
||||
f := setup()
|
||||
defer f.cleanup()
|
||||
|
||||
oldValue, oldOK := os.LookupEnv("SHLVL")
|
||||
|
||||
Script(f.fds(), []string{"print $E:SHLVL"}, &ScriptConfig{Cmd: true})
|
||||
f.testOut(t, 1, wantSHLVL)
|
||||
|
||||
// Test that state of SHLVL is restored.
|
||||
newValue, newOK := os.LookupEnv("SHLVL")
|
||||
if newValue != oldValue {
|
||||
t.Errorf("SHLVL not restored, %q -> %q", oldValue, newValue)
|
||||
}
|
||||
if oldOK != newOK {
|
||||
t.Errorf("SHLVL existence not restored, %v -> %v", oldOK, newOK)
|
||||
}
|
||||
}
|
|
@ -48,6 +48,8 @@ Version 0.14 has not been released yet. It is planned to be released on
|
|||
|
||||
- Elvish now uses `$XDG_RUNTIME_DIR` to keep runtime files if possible.
|
||||
|
||||
- Elvish now increments the `$SHLVL` environment variable.
|
||||
|
||||
# Notable bugfixes
|
||||
|
||||
- Elvish no longer crashes when redirecting to a high FD
|
||||
|
|
Loading…
Reference in New Issue
Block a user