github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/shell/shell.go (about) 1 // Package shell is the entry point for the terminal interface of Elvish. 2 package shell 3 4 import ( 5 "os" 6 "os/signal" 7 "strconv" 8 "time" 9 10 "src.elv.sh/pkg/cli/term" 11 "src.elv.sh/pkg/env" 12 "src.elv.sh/pkg/eval" 13 "src.elv.sh/pkg/logutil" 14 "src.elv.sh/pkg/parse" 15 "src.elv.sh/pkg/prog" 16 "src.elv.sh/pkg/sys" 17 ) 18 19 var logger = logutil.GetLogger("[shell] ") 20 21 // Program is the shell subprogram. 22 var Program prog.Program = program{} 23 24 type program struct{} 25 26 func (program) ShouldRun(*prog.Flags) bool { return true } 27 28 func (program) Run(fds [3]*os.File, f *prog.Flags, args []string) error { 29 p := MakePaths(fds[2], 30 Paths{Bin: f.Bin, Sock: f.Sock, Db: f.DB}) 31 if f.NoRc { 32 p.Rc = "" 33 } 34 if len(args) > 0 { 35 exit := Script( 36 fds, args, &ScriptConfig{ 37 Paths: p, 38 Cmd: f.CodeInArg, CompileOnly: f.CompileOnly, JSON: f.JSON}) 39 return prog.Exit(exit) 40 } 41 Interact(fds, &InteractConfig{SpawnDaemon: true, Paths: p}) 42 return nil 43 } 44 45 func setupShell(fds [3]*os.File, p Paths, spawn bool) (*eval.Evaler, func()) { 46 restoreTTY := term.SetupGlobal() 47 ev := InitRuntime(fds[2], p, spawn) 48 restoreSHLVL := incSHLVL() 49 sigCh := sys.NotifySignals() 50 51 go func() { 52 for sig := range sigCh { 53 logger.Println("signal", sig) 54 handleSignal(sig, fds[2]) 55 } 56 }() 57 58 return ev, func() { 59 signal.Stop(sigCh) 60 restoreSHLVL() 61 CleanupRuntime(fds[2], ev) 62 restoreTTY() 63 } 64 } 65 66 func evalInTTY(ev *eval.Evaler, fds [3]*os.File, src parse.Source) (float64, error) { 67 start := time.Now() 68 ports, cleanup := eval.PortsFromFiles(fds, ev.ValuePrefix()) 69 defer cleanup() 70 err := ev.Eval(src, eval.EvalCfg{ 71 Ports: ports, Interrupt: eval.ListenInterrupts, PutInFg: true}) 72 end := time.Now() 73 return end.Sub(start).Seconds(), err 74 } 75 76 func incSHLVL() func() { 77 restoreSHLVL := saveEnv(env.SHLVL) 78 79 i, err := strconv.Atoi(os.Getenv(env.SHLVL)) 80 if err != nil { 81 i = 0 82 } 83 os.Setenv(env.SHLVL, strconv.Itoa(i+1)) 84 85 return restoreSHLVL 86 } 87 88 func saveEnv(name string) func() { 89 v, ok := os.LookupEnv(name) 90 if ok { 91 return func() { os.Setenv(name, v) } 92 } 93 return func() { os.Unsetenv(name) } 94 }