github.com/klaytn/klaytn@v1.12.1/console/prompter.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from console/prompter.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package console 22 23 import ( 24 "fmt" 25 "strings" 26 27 "github.com/peterh/liner" 28 ) 29 30 // Stdin holds the stdin line reader (also using stdout for printing prompts). 31 // Only this reader may be used for input because it keeps an internal buffer. 32 var Stdin = newTerminalPrompter() 33 34 // UserPrompter defines the methods needed by the console to promt the user for 35 // various types of inputs. 36 type UserPrompter interface { 37 // PromptInput displays the given prompt to the user and requests some textual 38 // data to be entered, returning the input of the user. 39 PromptInput(prompt string) (string, error) 40 41 // PromptPassword displays the given prompt to the user and requests some textual 42 // data to be entered, but one which must not be echoed out into the terminal. 43 // The method returns the input provided by the user. 44 PromptPassword(prompt string) (string, error) 45 46 // PromptConfirm displays the given prompt to the user and requests a boolean 47 // choice to be made, returning that choice. 48 PromptConfirm(prompt string) (bool, error) 49 50 // SetHistory sets the input scrollback history that the prompter will allow 51 // the user to scroll back to. 52 SetHistory(history []string) 53 54 // AppendHistory appends an entry to the scrollback history. It should be called 55 // if and only if the prompt to append was a valid command. 56 AppendHistory(command string) 57 58 // ClearHistory clears the entire history 59 ClearHistory() 60 61 // SetWordCompleter sets the completion function that the prompter will call to 62 // fetch completion candidates when the user presses tab. 63 SetWordCompleter(completer WordCompleter) 64 } 65 66 // WordCompleter takes the currently edited line with the cursor position and 67 // returns the completion candidates for the partial word to be completed. If 68 // the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, 69 // wo!!!", 9) is passed to the completer which may returns ("Hello, ", {"world", 70 // "Word"}, "!!!") to have "Hello, world!!!". 71 type WordCompleter func(line string, pos int) (string, []string, string) 72 73 // terminalPrompter is a UserPrompter backed by the liner package. It supports 74 // prompting the user for various input, among others for non-echoing password 75 // input. 76 type terminalPrompter struct { 77 *liner.State 78 warned bool 79 supported bool 80 normalMode liner.ModeApplier 81 rawMode liner.ModeApplier 82 } 83 84 // newTerminalPrompter creates a liner based user input prompter working off the 85 // standard input and output streams. 86 func newTerminalPrompter() *terminalPrompter { 87 p := new(terminalPrompter) 88 // Get the original mode before calling NewLiner. 89 // This is usually regular "cooked" mode where characters echo. 90 normalMode, _ := liner.TerminalMode() 91 // Turn on liner. It switches to raw mode. 92 p.State = liner.NewLiner() 93 rawMode, err := liner.TerminalMode() 94 if err != nil || !liner.TerminalSupported() { 95 p.supported = false 96 } else { 97 p.supported = true 98 p.normalMode = normalMode 99 p.rawMode = rawMode 100 // Switch back to normal mode while we're not prompting. 101 normalMode.ApplyMode() 102 } 103 p.SetCtrlCAborts(true) 104 p.SetTabCompletionStyle(liner.TabPrints) 105 p.SetMultiLineMode(true) 106 return p 107 } 108 109 // PromptInput displays the given prompt to the user and requests some textual 110 // data to be entered, returning the input of the user. 111 func (p *terminalPrompter) PromptInput(prompt string) (string, error) { 112 if p.supported { 113 p.rawMode.ApplyMode() 114 defer p.normalMode.ApplyMode() 115 } else { 116 // liner tries to be smart about printing the prompt 117 // and doesn't print anything if input is redirected. 118 // Un-smart it by printing the prompt always. 119 fmt.Print(prompt) 120 prompt = "" 121 defer fmt.Println() 122 } 123 return p.State.Prompt(prompt) 124 } 125 126 // PromptPassword displays the given prompt to the user and requests some textual 127 // data to be entered, but one which must not be echoed out into the terminal. 128 // The method returns the input provided by the user. 129 func (p *terminalPrompter) PromptPassword(prompt string) (passwd string, err error) { 130 if p.supported { 131 p.rawMode.ApplyMode() 132 defer p.normalMode.ApplyMode() 133 return p.State.PasswordPrompt(prompt) 134 } 135 if !p.warned { 136 fmt.Println("!! Unsupported terminal, password will be echoed.") 137 p.warned = true 138 } 139 // Just as in Prompt, handle printing the prompt here instead of relying on liner. 140 fmt.Print(prompt) 141 passwd, err = p.State.Prompt("") 142 fmt.Println() 143 return passwd, err 144 } 145 146 // PromptConfirm displays the given prompt to the user and requests a boolean 147 // choice to be made, returning that choice. 148 func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) { 149 input, err := p.Prompt(prompt + " [y/N] ") 150 if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" { 151 return true, nil 152 } 153 return false, err 154 } 155 156 // SetHistory sets the input scrollback history that the prompter will allow 157 // the user to scroll back to. 158 func (p *terminalPrompter) SetHistory(history []string) { 159 p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n"))) 160 } 161 162 // AppendHistory appends an entry to the scrollback history. 163 func (p *terminalPrompter) AppendHistory(command string) { 164 p.State.AppendHistory(command) 165 } 166 167 // ClearHistory clears the entire history 168 func (p *terminalPrompter) ClearHistory() { 169 p.State.ClearHistory() 170 } 171 172 // SetWordCompleter sets the completion function that the prompter will call to 173 // fetch completion candidates when the user presses tab. 174 func (p *terminalPrompter) SetWordCompleter(completer WordCompleter) { 175 p.State.SetWordCompleter(liner.WordCompleter(completer)) 176 }