summaryrefslogtreecommitdiffstats
path: root/src/cmd/pprof/readlineui.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/pprof/readlineui.go')
-rw-r--r--src/cmd/pprof/readlineui.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/cmd/pprof/readlineui.go b/src/cmd/pprof/readlineui.go
new file mode 100644
index 0000000..0c9fafd
--- /dev/null
+++ b/src/cmd/pprof/readlineui.go
@@ -0,0 +1,120 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains a driver.UI implementation
+// that provides the readline functionality if possible.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build !appengine
+// +build !android
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/google/pprof/driver"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+func init() {
+ newUI = newReadlineUI
+}
+
+// readlineUI implements driver.UI interface using the
+// golang.org/x/crypto/ssh/terminal package.
+// The upstream pprof command implements the same functionality
+// using the github.com/chzyer/readline package.
+type readlineUI struct {
+ term *terminal.Terminal
+}
+
+func newReadlineUI() driver.UI {
+ // disable readline UI in dumb terminal. (golang.org/issue/26254)
+ if v := strings.ToLower(os.Getenv("TERM")); v == "" || v == "dumb" {
+ return nil
+ }
+ // test if we can use terminal.ReadLine
+ // that assumes operation in the raw mode.
+ oldState, err := terminal.MakeRaw(0)
+ if err != nil {
+ return nil
+ }
+ terminal.Restore(0, oldState)
+
+ rw := struct {
+ io.Reader
+ io.Writer
+ }{os.Stdin, os.Stderr}
+ return &readlineUI{term: terminal.NewTerminal(rw, "")}
+}
+
+// Read returns a line of text (a command) read from the user.
+// prompt is printed before reading the command.
+func (r *readlineUI) ReadLine(prompt string) (string, error) {
+ r.term.SetPrompt(prompt)
+
+ // skip error checking because we tested it
+ // when creating this readlineUI initially.
+ oldState, _ := terminal.MakeRaw(0)
+ defer terminal.Restore(0, oldState)
+
+ s, err := r.term.ReadLine()
+ return s, err
+}
+
+// Print shows a message to the user.
+// It formats the text as fmt.Print would and adds a final \n if not already present.
+// For line-based UI, Print writes to standard error.
+// (Standard output is reserved for report data.)
+func (r *readlineUI) Print(args ...interface{}) {
+ r.print(false, args...)
+}
+
+// PrintErr shows an error message to the user.
+// It formats the text as fmt.Print would and adds a final \n if not already present.
+// For line-based UI, PrintErr writes to standard error.
+func (r *readlineUI) PrintErr(args ...interface{}) {
+ r.print(true, args...)
+}
+
+func (r *readlineUI) print(withColor bool, args ...interface{}) {
+ text := fmt.Sprint(args...)
+ if !strings.HasSuffix(text, "\n") {
+ text += "\n"
+ }
+ if withColor {
+ text = colorize(text)
+ }
+ fmt.Fprint(r.term, text)
+}
+
+// colorize prints the msg in red using ANSI color escapes.
+func colorize(msg string) string {
+ const red = 31
+ var colorEscape = fmt.Sprintf("\033[0;%dm", red)
+ var colorResetEscape = "\033[0m"
+ return colorEscape + msg + colorResetEscape
+}
+
+// IsTerminal reports whether the UI is known to be tied to an
+// interactive terminal (as opposed to being redirected to a file).
+func (r *readlineUI) IsTerminal() bool {
+ const stdout = 1
+ return terminal.IsTerminal(stdout)
+}
+
+// WantBrowser indicates whether browser should be opened with the -http option.
+func (r *readlineUI) WantBrowser() bool {
+ return r.IsTerminal()
+}
+
+// SetAutoComplete instructs the UI to call complete(cmd) to obtain
+// the auto-completion of cmd, if the UI supports auto-completion at all.
+func (r *readlineUI) SetAutoComplete(complete func(string) string) {
+ // TODO: Implement auto-completion support.
+}