| // Copyright (c) The OpenTofu Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| // Copyright (c) 2023 HashiCorp, Inc. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| package command | |
| import ( | |
| "errors" | |
| "fmt" | |
| "io" | |
| "os" | |
| "strings" | |
| "github.com/opentofu/opentofu/internal/command/views" | |
| "github.com/opentofu/opentofu/internal/repl" | |
| "github.com/opentofu/opentofu/internal/tfdiags" | |
| "github.com/chzyer/readline" | |
| ) | |
| func (c *ConsoleCommand) modeInteractive(session *repl.Session, view views.Console) int { | |
| // Configure input | |
| l, err := readline.NewEx(&readline.Config{ | |
| Prompt: "> ", | |
| InterruptPrompt: "^C", | |
| EOFPrompt: "exit", | |
| HistorySearchFold: true, | |
| Stdin: os.Stdin, | |
| Stdout: os.Stdout, | |
| Stderr: os.Stderr, | |
| }) | |
| if err != nil { | |
| view.Diagnostics(tfdiags.Diagnostics{}.Append(tfdiags.Sourceless( | |
| tfdiags.Error, | |
| "Plugins loading error", | |
| fmt.Sprintf("Error initializing console: %s", err), | |
| ))) | |
| return 1 | |
| } | |
| defer l.Close() | |
| var consoleState consoleBracketState | |
| for { | |
| // Read a line | |
| line, err := l.Readline() | |
| if errors.Is(err, readline.ErrInterrupt) { | |
| if len(line) == 0 { | |
| break | |
| } else { | |
| continue | |
| } | |
| } else if errors.Is(err, io.EOF) { | |
| break | |
| } | |
| line = strings.TrimSpace(line) | |
| // we update the state with the new line, so if we have open | |
| // brackets we know not to execute the command just yet | |
| fullCommand, openState := consoleState.UpdateState(line) | |
| if openState > 0 { | |
| // here there are open brackets somewhere, so we don't execute it | |
| // as we are in a bracket we update the prompt. we use one . per layer pf brackets | |
| l.SetPrompt(fmt.Sprintf("%s ", strings.Repeat(".", openState))) | |
| } else { | |
| out, exit, diags := session.Handle(fullCommand) | |
| if diags.HasErrors() { | |
| view.Diagnostics(diags) | |
| } | |
| if exit { | |
| break | |
| } | |
| // clear the state and buffer as we have executed a command | |
| // we also reset the prompt | |
| l.SetPrompt("> ") | |
| view.Output(out) | |
| } | |
| } | |
| return 0 | |
| } |