Source file src/cmd/pprof/readlineui.go
Documentation: cmd/pprof
1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file contains a driver.UI implementation 6 // that provides the readline functionality if possible. 7 8 //go:build (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows) && !appengine && !android 9 // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows 10 // +build !appengine 11 // +build !android 12 13 package main 14 15 import ( 16 "fmt" 17 "io" 18 "os" 19 "strings" 20 21 "github.com/google/pprof/driver" 22 "golang.org/x/term" 23 ) 24 25 func init() { 26 newUI = newReadlineUI 27 } 28 29 // readlineUI implements driver.UI interface using the 30 // golang.org/x/term package. 31 // The upstream pprof command implements the same functionality 32 // using the github.com/chzyer/readline package. 33 type readlineUI struct { 34 term *term.Terminal 35 } 36 37 func newReadlineUI() driver.UI { 38 // disable readline UI in dumb terminal. (golang.org/issue/26254) 39 if v := strings.ToLower(os.Getenv("TERM")); v == "" || v == "dumb" { 40 return nil 41 } 42 // test if we can use term.ReadLine 43 // that assumes operation in the raw mode. 44 oldState, err := term.MakeRaw(0) 45 if err != nil { 46 return nil 47 } 48 term.Restore(0, oldState) 49 50 rw := struct { 51 io.Reader 52 io.Writer 53 }{os.Stdin, os.Stderr} 54 return &readlineUI{term: term.NewTerminal(rw, "")} 55 } 56 57 // Read returns a line of text (a command) read from the user. 58 // prompt is printed before reading the command. 59 func (r *readlineUI) ReadLine(prompt string) (string, error) { 60 r.term.SetPrompt(prompt) 61 62 // skip error checking because we tested it 63 // when creating this readlineUI initially. 64 oldState, _ := term.MakeRaw(0) 65 defer term.Restore(0, oldState) 66 67 s, err := r.term.ReadLine() 68 return s, err 69 } 70 71 // Print shows a message to the user. 72 // It formats the text as fmt.Print would and adds a final \n if not already present. 73 // For line-based UI, Print writes to standard error. 74 // (Standard output is reserved for report data.) 75 func (r *readlineUI) Print(args ...interface{}) { 76 r.print(false, args...) 77 } 78 79 // PrintErr shows an error message to the user. 80 // It formats the text as fmt.Print would and adds a final \n if not already present. 81 // For line-based UI, PrintErr writes to standard error. 82 func (r *readlineUI) PrintErr(args ...interface{}) { 83 r.print(true, args...) 84 } 85 86 func (r *readlineUI) print(withColor bool, args ...interface{}) { 87 text := fmt.Sprint(args...) 88 if !strings.HasSuffix(text, "\n") { 89 text += "\n" 90 } 91 if withColor { 92 text = colorize(text) 93 } 94 fmt.Fprint(r.term, text) 95 } 96 97 // colorize prints the msg in red using ANSI color escapes. 98 func colorize(msg string) string { 99 const red = 31 100 var colorEscape = fmt.Sprintf("\033[0;%dm", red) 101 var colorResetEscape = "\033[0m" 102 return colorEscape + msg + colorResetEscape 103 } 104 105 // IsTerminal reports whether the UI is known to be tied to an 106 // interactive terminal (as opposed to being redirected to a file). 107 func (r *readlineUI) IsTerminal() bool { 108 const stdout = 1 109 return term.IsTerminal(stdout) 110 } 111 112 // WantBrowser indicates whether browser should be opened with the -http option. 113 func (r *readlineUI) WantBrowser() bool { 114 return r.IsTerminal() 115 } 116 117 // SetAutoComplete instructs the UI to call complete(cmd) to obtain 118 // the auto-completion of cmd, if the UI supports auto-completion at all. 119 func (r *readlineUI) SetAutoComplete(complete func(string) string) { 120 // TODO: Implement auto-completion support. 121 } 122