Source file src/cmd/pprof/readlineui.go

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

View as plain text