package shell

import (
	
	
	
	
	
	
	

	
	
	
	
	
	
	
)

// InteractiveRescueShell determines whether a panic results in a rescue shell
// being launched. It should be set to false by interactive mode unit tests.
var interactiveRescueShell bool = true

// InteractConfig keeps configuration for the interactive mode.
type InteractConfig struct {
	SpawnDaemon bool
	Paths       Paths
}

// Interactive mode panic handler.
func () {
	 := recover()
	if  != nil {
		println()
		print(sys.DumpStack())
		println()
		fmt.Println()
		println("\nExecing recovery shell /bin/sh")
		syscall.Exec("/bin/sh", []string{"/bin/sh"}, os.Environ())
	}
}

// Interact runs an interactive shell session.
func ( [3]*os.File,  *InteractConfig) {
	if interactiveRescueShell {
		defer handlePanic()
	}
	,  := setupShell(, .Paths, .SpawnDaemon)
	defer ()

	// Build Editor.
	var  editor
	if sys.IsATTY([0]) {
		 := edit.NewEditor(cli.NewTTY([0], [2]), , .DaemonClient())
		.AddBuiltin(eval.NsBuilder{}.AddNs("edit", .Ns()).Ns())
		 = 
	} else {
		 = newMinEditor([0], [2])
	}

	// Source rc.elv.
	if .Paths.Rc != "" {
		 := sourceRC(, , , .Paths.Rc)
		if  != nil {
			diag.ShowError([2], )
		}
	}

	term.Sanitize([0], [2])

	 := time.Second
	 := 0

	for {
		++

		,  := .ReadCode()
		if  == io.EOF {
			break
		} else if  != nil {
			fmt.Fprintln([2], "Editor error:", )
			if ,  := .(*minEditor); ! {
				fmt.Fprintln([2], "Falling back to basic line editor")
				 = newMinEditor([0], [2])
			} else {
				fmt.Fprintln([2], "Don't know what to do, pid is", os.Getpid())
				fmt.Fprintln([2], "Restarting editor in", )
				time.Sleep()
				if  < time.Minute {
					 *= 2
				}
			}
			continue
		}

		// No error; reset cooldown.
		 = time.Second

		// Execute the command line only if it is not entirely whitespace. This keeps side-effects,
		// such as executing `$edit:after-command` hooks, from occurring when we didn't actually
		// evaluate any code entered by the user.
		if strings.TrimSpace() == "" {
			continue
		}
		 := parse.Source{Name: fmt.Sprintf("[tty %v]", ), Code: }
		,  := evalInTTY(, , )
		.RunAfterCommandHooks(, , )
		term.Sanitize([0], [2])
		if  != nil {
			diag.ShowError([2], )
		}
	}
}

func ( [3]*os.File,  *eval.Evaler,  eval.Editor,  string) error {
	,  := filepath.Abs()
	if  != nil {
		return fmt.Errorf("cannot get full path of rc.elv: %v", )
	}
	,  := readFileUTF8()
	if  != nil {
		if os.IsNotExist() {
			return nil
		}
		return 
	}
	 := parse.Source{Name: , Code: , IsFile: true}
	,  := evalInTTY(, , )
	.RunAfterCommandHooks(, , )
	return 
}