aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/util/io/AnsiTerminal.java
blob: 93bc12af1086d410497319ea19bcad8e750de850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.util.io;

import java.io.IOException;
import java.io.OutputStream;

/**
 * A class which encapsulates the fancy curses-type stuff that you can do using
 * standard ANSI terminal control sequences.
 */
public class AnsiTerminal {
  private static final byte[] ESC = {27, (byte) '['};
  private static final byte BEL = 7;
  private static final byte UP = (byte) 'A';
  private static final byte ERASE_LINE = (byte) 'K';
  private static final byte SET_GRAPHICS = (byte) 'm';
  private static final byte TEXT_BOLD = (byte) '1';
  private static final byte[] SET_TERM_TITLE = {27, (byte) ']', (byte) '0', (byte) ';'};

  public static final String FG_BLACK = "30";
  public static final String FG_RED = "31";
  public static final String FG_GREEN = "32";
  public static final String FG_YELLOW = "33";
  public static final String FG_BLUE = "34";
  public static final String FG_MAGENTA = "35";
  public static final String FG_CYAN = "36";
  public static final String FG_GRAY = "37";
  public static final String BG_BLACK = "40";
  public static final String BG_RED = "41";
  public static final String BG_GREEN = "42";
  public static final String BG_YELLOW = "43";
  public static final String BG_BLUE = "44";
  public static final String BG_MAGENTA = "45";
  public static final String BG_CYAN = "46";
  public static final String BG_GRAY = "47";

  public static byte[] CR = { 13 };

  private final OutputStream out;

  /**
   * Creates an AnsiTerminal object wrapping an output stream which is going to
   * be displayed in an ANSI compatible terminal or shell window.
   *
   * @param out the output stream
   */
  public AnsiTerminal(OutputStream out) {
    this.out = out;
  }

  /**
   * Moves the cursor upwards by a specified number of lines. This will not
   * cause any scrolling if it tries to move above the top of the terminal
   * window.
   */
  public void cursorUp(int numLines) throws IOException {
    writeBytes(ESC, ("" + numLines).getBytes(), new byte[] { UP });
  }

  /**
   * Clear the current terminal line from the cursor position to the end.
   */
  public void clearLine() throws IOException {
    writeEscapeSequence(ERASE_LINE);
  }

  /**
   * Makes any text output to the terminal appear in bold.
   */
  public void textBold() throws IOException {
    writeEscapeSequence(TEXT_BOLD,  SET_GRAPHICS);
  }

  /**
   * Set the color of the foreground or background of the terminal.
   *
   * @param color one of the foreground or background color
   * constants
   */
  public void setTextColor(String color) throws IOException {
    writeBytes(ESC, color.getBytes(), new byte[] { SET_GRAPHICS });
  }

  /**
   * Resets the terminal colors and fonts to defaults.
   */
  public void resetTerminal() throws IOException {
    writeEscapeSequence((byte)'0', (byte)'m');
  }

  /**
   * Makes text print on the terminal in red.
   */
  public void textRed() throws IOException {
    setTextColor(FG_RED);
  }

  /**
   * Makes text print on the terminal in blue.
   */
  public void textBlue() throws IOException {
    setTextColor(FG_BLUE);
  }

  /**
   * Makes text print on the terminal in red.
   */
  public void textGreen() throws IOException {
    setTextColor(FG_GREEN);
  }

  /**
   * Makes text print on the terminal in red.
   */
  public void textMagenta() throws IOException {
    setTextColor(FG_MAGENTA);
  }

  /**
   * Set the terminal title.
   */
  public void setTitle(String title) throws IOException {
    writeBytes(SET_TERM_TITLE, title.getBytes(), new byte[] { BEL });
  }

  /**
   * Writes a string to the terminal using the current font, color and cursor
   * position settings.
   *
   * @param text the text to write
   */
  public void writeString(String text) throws IOException {
    out.write(text.getBytes());
  }

  /**
   * Writes a byte sequence to the terminal using the current font, color and
   * cursor position settings.
   *
   * @param bytes the bytes to write
   */
  public void writeBytes(byte[] bytes) throws IOException {
    out.write(bytes);
  }

  /**
   * Utility method which makes it easier to generate the control sequences for
   * the terminal.
   *
   * @param bytes bytes which should be prefixed with the terminal escape
   *        sequence to produce a valid control sequence
   */
  private void writeEscapeSequence(byte... bytes) throws IOException {
    writeBytes(ESC, bytes);
  }

  /**
   * Utility method for generating control sequences. Takes a collection of byte
   * arrays, which contain the components of a control sequence, concatenates
   * them, and prints them to the terminal.
   *
   * @param stuff the byte arrays that make up the sequence to be sent to the
   *        terminal
   */
  private void writeBytes(byte[]... stuff) throws IOException {
    for (byte[] bytes : stuff) {
      out.write(bytes);
    }
  }

  /**
   * Sends a carriage return to the terminal.
   */
  public void cr() throws IOException {
    writeBytes(CR);
  }

  /**
   * Flushes the underlying stream.
   * This class does not do any buffering of its own, but the underlying
   * OutputStream may.
   */
  public void flush() throws IOException {
    out.flush();
  }
}