blob: 26e0e342fa6c6787636060c3cff8aa4bd93d16f4 [file] [log] [blame]
Dan Willemsenb82471a2018-05-17 16:37:09 -07001// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package terminal provides a set of interfaces that can be used to interact
16// with the terminal (including falling back when the terminal is detected to
17// be a redirect or other dumb terminal)
18package terminal
19
20import (
21 "fmt"
22 "io"
23 "os"
Dan Willemsenb82471a2018-05-17 16:37:09 -070024)
25
26// Writer provides an interface to write temporary and permanent messages to
27// the terminal.
28//
29// The terminal is considered to be a dumb terminal if TERM==dumb, or if a
30// terminal isn't detected on stdout/stderr (generally because it's a pipe or
31// file). Dumb terminals will strip out all ANSI escape sequences, including
32// colors.
33type Writer interface {
34 // Print prints the string to the terminal, overwriting any current
35 // status being displayed.
36 //
37 // On a dumb terminal, the status messages will be kept.
38 Print(str string)
39
Dan Willemsenb82471a2018-05-17 16:37:09 -070040 // Finish ensures that the output ends with a newline (preserving any
41 // current status line that is current displayed).
42 //
43 // This does nothing on dumb terminals.
44 Finish()
45
46 // Write implements the io.Writer interface. This is primarily so that
47 // the logger can use this interface to print to stderr without
48 // breaking the other semantics of this interface.
49 //
50 // Try to use any of the other functions if possible.
51 Write(p []byte) (n int, err error)
52
53 isSmartTerminal() bool
Colin Crossce525352019-06-08 18:58:00 -070054 termWidth() (int, bool)
Dan Willemsenb82471a2018-05-17 16:37:09 -070055}
56
57// NewWriter creates a new Writer based on the stdio and the TERM
58// environment variable.
59func NewWriter(stdio StdioInterface) Writer {
60 w := &writerImpl{
61 stdio: stdio,
Dan Willemsenb82471a2018-05-17 16:37:09 -070062 }
63
Dan Willemsenb82471a2018-05-17 16:37:09 -070064 return w
65}
66
67type writerImpl struct {
68 stdio StdioInterface
Dan Willemsenb82471a2018-05-17 16:37:09 -070069}
70
71func (w *writerImpl) Print(str string) {
Dan Willemsenf78a7342018-07-12 21:26:10 -070072 fmt.Fprint(w.stdio.Stdout(), str)
Dan Willemsenb82471a2018-05-17 16:37:09 -070073 if len(str) == 0 || str[len(str)-1] != '\n' {
Dan Willemsenf78a7342018-07-12 21:26:10 -070074 fmt.Fprint(w.stdio.Stdout(), "\n")
Dan Willemsenb82471a2018-05-17 16:37:09 -070075 }
76}
77
Colin Crossce525352019-06-08 18:58:00 -070078func (w *writerImpl) Finish() {}
Dan Willemsenb82471a2018-05-17 16:37:09 -070079
80func (w *writerImpl) Write(p []byte) (n int, err error) {
Colin Crossce525352019-06-08 18:58:00 -070081 return w.stdio.Stdout().Write(p)
82}
83
84func (w *writerImpl) isSmartTerminal() bool {
85 return isSmartTerminal(w.stdio.Stdout())
86}
87
88func (w *writerImpl) termWidth() (int, bool) {
89 return termWidth(w.stdio.Stdout())
Dan Willemsenb82471a2018-05-17 16:37:09 -070090}
91
92// StdioInterface represents a set of stdin/stdout/stderr Reader/Writers
93type StdioInterface interface {
94 Stdin() io.Reader
95 Stdout() io.Writer
96 Stderr() io.Writer
97}
98
99// StdioImpl uses the OS stdin/stdout/stderr to implement StdioInterface
100type StdioImpl struct{}
101
102func (StdioImpl) Stdin() io.Reader { return os.Stdin }
103func (StdioImpl) Stdout() io.Writer { return os.Stdout }
104func (StdioImpl) Stderr() io.Writer { return os.Stderr }
105
106var _ StdioInterface = StdioImpl{}
107
108type customStdio struct {
109 stdin io.Reader
110 stdout io.Writer
111 stderr io.Writer
112}
113
114func NewCustomStdio(stdin io.Reader, stdout, stderr io.Writer) StdioInterface {
115 return customStdio{stdin, stdout, stderr}
116}
117
118func (c customStdio) Stdin() io.Reader { return c.stdin }
119func (c customStdio) Stdout() io.Writer { return c.stdout }
120func (c customStdio) Stderr() io.Writer { return c.stderr }
121
122var _ StdioInterface = customStdio{}