text: package cli
  
  import (
  	"bufio"
  	"errors"
  	"fmt"
  	"io"
  	"os"
  	"os/signal"
  	"strings"
  
  	"github.com/bgentry/speakeasy"
  	"github.com/mattn/go-isatty"
  )
  
  // Ui is an interface for interacting with the terminal, or "interface"
  // of a CLI. This abstraction doesn't have to be used, but helps provide
  // a simple, layerable way to manage user interactions.
  type Ui interface {
  	// Ask asks the user for input using the given query. The response is
  	// returned as the given string, or an error.
  	Ask(string) (string, error)
  
  	// AskSecret asks the user for input using the given query, but does not echo
  	// the keystrokes to the terminal.
  	AskSecret(string) (string, error)
  
  	// Output is called for normal standard output.
  	Output(string)
  
  	// Info is called for information related to the previous output.
  	// In general this may be the exact same as Output, but this gives
  	// Ui implementors some flexibility with output formats.
  	Info(string)
  
  	// Error is used for any error messages that might appear on standard
  	// error.
  	Error(string)
  
  	// Warn is used for any warning messages that might appear on standard
  	// error.
  	Warn(string)
  }
  
  // BasicUi is an implementation of Ui that just outputs to the given
  // writer. This UI is not threadsafe by default, but you can wrap it
  // in a ConcurrentUi to make it safe.
  type BasicUi struct {
  	Reader      io.Reader
  	Writer      io.Writer
  	ErrorWriter io.Writer
  }
  
  func (u *BasicUi) Ask(query string) (string, error) {
  	return u.ask(query, false)
  }
  
  func (u *BasicUi) AskSecret(query string) (string, error) {
  	return u.ask(query, true)
  }
  
  func (u *BasicUi) ask(query string, secret bool) (string, error) {
  	if _, err := fmt.Fprint(u.Writer, query+" "); err != nil {
  		return "", err
  	}
  
  	// Register for interrupts so that we can catch it and immediately
  	// return...
  	sigCh := make(chan os.Signal, 1)
  	signal.Notify(sigCh, os.Interrupt)
  	defer signal.Stop(sigCh)
  
  	// Ask for input in a go-routine so that we can ignore it.
  	errCh := make(chan error, 1)
  	lineCh := make(chan string, 1)
  	go func() {
  		var line string
  		var err error
  		if secret && isatty.IsTerminal(os.Stdin.Fd()) {
  			line, err = speakeasy.Ask("")
  		} else {
  			r := bufio.NewReader(u.Reader)
  			line, err = r.ReadString('\n')
  		}
  		if err != nil {
  			errCh <- err
  			return
  		}
  
  		lineCh <- strings.TrimRight(line, "\r\n")
  	}()
  
  	select {
  	case err := <-errCh:
  		return "", err
  	case line := <-lineCh:
  		return line, nil
  	case <-sigCh:
  		// Print a newline so that any further output starts properly
  		// on a new line.
  		fmt.Fprintln(u.Writer)
  
  		return "", errors.New("interrupted")
  	}
  }
  
  func (u *BasicUi) Error(message string) {
  	w := u.Writer
  	if u.ErrorWriter != nil {
  		w = u.ErrorWriter
  	}
  
  	fmt.Fprint(w, message)
  	fmt.Fprint(w, "\n")
  }
  
  func (u *BasicUi) Info(message string) {
  	u.Output(message)
  }
  
  func (u *BasicUi) Output(message string) {
  	fmt.Fprint(u.Writer, message)
  	fmt.Fprint(u.Writer, "\n")
  }
  
  func (u *BasicUi) Warn(message string) {
  	u.Error(message)
  }
  
  // PrefixedUi is an implementation of Ui that prefixes messages.
  type PrefixedUi struct {
  	AskPrefix       string
  	AskSecretPrefix string
  	OutputPrefix    string
  	InfoPrefix      string
  	ErrorPrefix     string
  	WarnPrefix      string
  	Ui              Ui
  }
  
  func (u *PrefixedUi) Ask(query string) (string, error) {
  	if query != "" {
  		query = fmt.Sprintf("%s%s", u.AskPrefix, query)
  	}
  
  	return u.Ui.Ask(query)
  }
  
  func (u *PrefixedUi) AskSecret(query string) (string, error) {
  	if query != "" {
  		query = fmt.Sprintf("%s%s", u.AskSecretPrefix, query)
  	}
  
  	return u.Ui.AskSecret(query)
  }
  
  func (u *PrefixedUi) Error(message string) {
  	if message != "" {
  		message = fmt.Sprintf("%s%s", u.ErrorPrefix, message)
  	}
  
  	u.Ui.Error(message)
  }
  
  func (u *PrefixedUi) Info(message string) {
  	if message != "" {
  		message = fmt.Sprintf("%s%s", u.InfoPrefix, message)
  	}
  
  	u.Ui.Info(message)
  }
  
  func (u *PrefixedUi) Output(message string) {
  	if message != "" {
  		message = fmt.Sprintf("%s%s", u.OutputPrefix, message)
  	}
  
  	u.Ui.Output(message)
  }
  
  func (u *PrefixedUi) Warn(message string) {
  	if message != "" {
  		message = fmt.Sprintf("%s%s", u.WarnPrefix, message)
  	}
  
  	u.Ui.Warn(message)
  }
  