gitlab.com/apertussolutions/u-root@v7.0.0+incompatible/cmds/core/elvish/program/shell/interact.go (about)

     1  package shell
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"os/signal"
     9  	"path/filepath"
    10  	"syscall"
    11  	"time"
    12  
    13  	"github.com/u-root/u-root/cmds/core/elvish/edit"
    14  	"github.com/u-root/u-root/cmds/core/elvish/eval"
    15  	"github.com/u-root/u-root/cmds/core/elvish/sys"
    16  	"github.com/u-root/u-root/cmds/core/elvish/util"
    17  )
    18  
    19  func interact(ev *eval.Evaler, dataDir string) {
    20  	// Build Editor.
    21  	var ed editor
    22  	if sys.IsATTY(os.Stdin) {
    23  		sigch := make(chan os.Signal)
    24  		signal.Notify(sigch, syscall.SIGHUP, syscall.SIGINT, sys.SIGWINCH)
    25  		ed = edit.NewEditor(os.Stdin, os.Stderr, sigch, ev)
    26  	} else {
    27  		ed = newMinEditor(os.Stdin, os.Stderr)
    28  	}
    29  	defer ed.Close()
    30  
    31  	// Source rc.elv.
    32  	if dataDir != "" {
    33  		err := sourceRC(ev, dataDir)
    34  		if err != nil {
    35  			util.PprintError(err)
    36  		}
    37  	}
    38  
    39  	// Build readLine function.
    40  	readLine := func() (string, error) {
    41  		return ed.ReadLine()
    42  	}
    43  
    44  	cooldown := time.Second
    45  	usingBasic := false
    46  	cmdNum := 0
    47  
    48  	for {
    49  		cmdNum++
    50  
    51  		line, err := readLine()
    52  
    53  		if err == io.EOF {
    54  			break
    55  		} else if err != nil {
    56  			fmt.Println("Editor error:", err)
    57  			if !usingBasic {
    58  				fmt.Println("Falling back to basic line editor")
    59  				readLine = basicReadLine
    60  				usingBasic = true
    61  			} else {
    62  				fmt.Println("Don't know what to do, pid is", os.Getpid())
    63  				fmt.Println("Restarting editor in", cooldown)
    64  				time.Sleep(cooldown)
    65  				if cooldown < time.Minute {
    66  					cooldown *= 2
    67  				}
    68  			}
    69  			continue
    70  		}
    71  
    72  		// No error; reset cooldown.
    73  		cooldown = time.Second
    74  
    75  		err = ev.EvalSource(eval.NewInteractiveSource(line))
    76  		if err != nil {
    77  			util.PprintError(err)
    78  		}
    79  	}
    80  }
    81  
    82  func sourceRC(ev *eval.Evaler, dataDir string) error {
    83  	absPath, err := filepath.Abs(filepath.Join(dataDir, "rc.elv"))
    84  	if err != nil {
    85  		return fmt.Errorf("cannot get full path of rc.elv: %v", err)
    86  	}
    87  	code, err := readFileUTF8(absPath)
    88  	if os.IsNotExist(err) {
    89  		return nil
    90  	}
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	return ev.SourceRC(eval.NewScriptSource("rc.elv", absPath, code))
    96  }
    97  
    98  func basicReadLine() (string, error) {
    99  	stdin := bufio.NewReaderSize(os.Stdin, 0)
   100  	return stdin.ReadString('\n')
   101  }