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  }