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