Black Lives Matter. Support the Equal Justice Initiative.

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

View as plain text