001 /*
002 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003 *
004 * This software is distributable under the BSD license. See the terms of the
005 * BSD license in the documentation provided with this software.
006 */
007 package jline;
008
009 import java.io.*;
010
011 /**
012 * A buffer that can contain ANSI text.
013 *
014 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
015 */
016 public class ANSIBuffer {
017 private boolean ansiEnabled = true;
018 private final StringBuffer ansiBuffer = new StringBuffer();
019 private final StringBuffer plainBuffer = new StringBuffer();
020
021 public ANSIBuffer() {
022 }
023
024 public ANSIBuffer(final String str) {
025 append(str);
026 }
027
028 public void setAnsiEnabled(final boolean ansi) {
029 this.ansiEnabled = ansi;
030 }
031
032 public boolean getAnsiEnabled() {
033 return this.ansiEnabled;
034 }
035
036 public String getAnsiBuffer() {
037 return ansiBuffer.toString();
038 }
039
040 public String getPlainBuffer() {
041 return plainBuffer.toString();
042 }
043
044 public String toString(final boolean ansi) {
045 return ansi ? getAnsiBuffer() : getPlainBuffer();
046 }
047
048 public String toString() {
049 return toString(ansiEnabled);
050 }
051
052 public ANSIBuffer append(final String str) {
053 ansiBuffer.append(str);
054 plainBuffer.append(str);
055
056 return this;
057 }
058
059 public ANSIBuffer attrib(final String str, final int code) {
060 ansiBuffer.append(ANSICodes.attrib(code)).append(str)
061 .append(ANSICodes.attrib(ANSICodes.OFF));
062 plainBuffer.append(str);
063
064 return this;
065 }
066
067 public ANSIBuffer red(final String str) {
068 return attrib(str, ANSICodes.FG_RED);
069 }
070
071 public ANSIBuffer blue(final String str) {
072 return attrib(str, ANSICodes.FG_BLUE);
073 }
074
075 public ANSIBuffer green(final String str) {
076 return attrib(str, ANSICodes.FG_GREEN);
077 }
078
079 public ANSIBuffer black(final String str) {
080 return attrib(str, ANSICodes.FG_BLACK);
081 }
082
083 public ANSIBuffer yellow(final String str) {
084 return attrib(str, ANSICodes.FG_YELLOW);
085 }
086
087 public ANSIBuffer magenta(final String str) {
088 return attrib(str, ANSICodes.FG_MAGENTA);
089 }
090
091 public ANSIBuffer cyan(final String str) {
092 return attrib(str, ANSICodes.FG_CYAN);
093 }
094
095 public ANSIBuffer bold(final String str) {
096 return attrib(str, ANSICodes.BOLD);
097 }
098
099 public ANSIBuffer underscore(final String str) {
100 return attrib(str, ANSICodes.UNDERSCORE);
101 }
102
103 public ANSIBuffer blink(final String str) {
104 return attrib(str, ANSICodes.BLINK);
105 }
106
107 public ANSIBuffer reverse(final String str) {
108 return attrib(str, ANSICodes.REVERSE);
109 }
110
111 public static class ANSICodes {
112 static final int OFF = 0;
113 static final int BOLD = 1;
114 static final int UNDERSCORE = 4;
115 static final int BLINK = 5;
116 static final int REVERSE = 7;
117 static final int CONCEALED = 8;
118 static final int FG_BLACK = 30;
119 static final int FG_RED = 31;
120 static final int FG_GREEN = 32;
121 static final int FG_YELLOW = 33;
122 static final int FG_BLUE = 34;
123 static final int FG_MAGENTA = 35;
124 static final int FG_CYAN = 36;
125 static final int FG_WHITE = 37;
126 static final char ESC = 27;
127
128 /**
129 * Constructor is private since this is a utility class.
130 */
131 private ANSICodes() {
132 }
133
134 /**
135 * Sets the screen mode. The mode will be one of the following values:
136 * <pre>
137 * mode description
138 * ----------------------------------------
139 * 0 40 x 148 x 25 monochrome (text)
140 * 1 40 x 148 x 25 color (text)
141 * 2 80 x 148 x 25 monochrome (text)
142 * 3 80 x 148 x 25 color (text)
143 * 4 320 x 148 x 200 4-color (graphics)
144 * 5 320 x 148 x 200 monochrome (graphics)
145 * 6 640 x 148 x 200 monochrome (graphics)
146 * 7 Enables line wrapping
147 * 13 320 x 148 x 200 color (graphics)
148 * 14 640 x 148 x 200 color (16-color graphics)
149 * 15 640 x 148 x 350 monochrome (2-color graphics)
150 * 16 640 x 148 x 350 color (16-color graphics)
151 * 17 640 x 148 x 480 monochrome (2-color graphics)
152 * 18 640 x 148 x 480 color (16-color graphics)
153 * 19 320 x 148 x 200 color (256-color graphics)
154 * </pre>
155 */
156 public static String setmode(final int mode) {
157 return ESC + "[=" + mode + "h";
158 }
159
160 /**
161 * Same as setmode () except for mode = 7, which disables line
162 * wrapping (useful for writing the right-most column without
163 * scrolling to the next line).
164 */
165 public static String resetmode(final int mode) {
166 return ESC + "[=" + mode + "l";
167 }
168
169 /**
170 * Clears the screen and moves the cursor to the home postition.
171 */
172 public static String clrscr() {
173 return ESC + "[2J";
174 }
175
176 /**
177 * Removes all characters from the current cursor position until
178 * the end of the line.
179 */
180 public static String clreol() {
181 return ESC + "[K";
182 }
183
184 /**
185 * Moves the cursor n positions to the left. If n is greater or
186 * equal to the current cursor column, the cursor is moved to the
187 * first column.
188 */
189 public static String left(final int n) {
190 return ESC + "[" + n + "D";
191 }
192
193 /**
194 * Moves the cursor n positions to the right. If n plus the current
195 * cursor column is greater than the rightmost column, the cursor
196 * is moved to the rightmost column.
197 */
198 public static String right(final int n) {
199 return ESC + "[" + n + "C";
200 }
201
202 /**
203 * Moves the cursor n rows up without changing the current column.
204 * If n is greater than or equal to the current row, the cursor is
205 * placed in the first row.
206 */
207 public static String up(final int n) {
208 return ESC + "[" + n + "A";
209 }
210
211 /**
212 * Moves the cursor n rows down. If n plus the current row is greater
213 * than the bottom row, the cursor is moved to the bottom row.
214 */
215 public static String down(final int n) {
216 return ESC + "[" + n + "B";
217 }
218
219 /*
220 * Moves the cursor to the given row and column. (1,1) represents
221 * the upper left corner. The lower right corner of a usual DOS
222 * screen is (25, 80).
223 */
224 public static String gotoxy(final int row, final int column) {
225 return ESC + "[" + row + ";" + column + "H";
226 }
227
228 /**
229 * Saves the current cursor position.
230 */
231 public static String save() {
232 return ESC + "[s";
233 }
234
235 /**
236 * Restores the saved cursor position.
237 */
238 public static String restore() {
239 return ESC + "[u";
240 }
241
242 /**
243 * Sets the character attribute. It will be
244 * one of the following character attributes:
245 *
246 * <pre>
247 * Text attributes
248 * 0 All attributes off
249 * 1 Bold on
250 * 4 Underscore (on monochrome display adapter only)
251 * 5 Blink on
252 * 7 Reverse video on
253 * 8 Concealed on
254 *
255 * Foreground colors
256 * 30 Black
257 * 31 Red
258 * 32 Green
259 * 33 Yellow
260 * 34 Blue
261 * 35 Magenta
262 * 36 Cyan
263 * 37 White
264 *
265 * Background colors
266 * 40 Black
267 * 41 Red
268 * 42 Green
269 * 43 Yellow
270 * 44 Blue
271 * 45 Magenta
272 * 46 Cyan
273 * 47 White
274 * </pre>
275 *
276 * The attributes remain in effect until the next attribute command
277 * is sent.
278 */
279 public static String attrib(final int attr) {
280 return ESC + "[" + attr + "m";
281 }
282
283 /**
284 * Sets the key with the given code to the given value. code must be
285 * derived from the following table, value must
286 * be any semicolon-separated
287 * combination of String (enclosed in double quotes) and numeric values.
288 * For example, to set F1 to the String "Hello F1", followed by a CRLF
289 * sequence, one can use: ANSI.setkey ("0;59", "\"Hello F1\";13;10").
290 * Heres's the table of key values:
291 * <pre>
292 * Key Code SHIFT+code CTRL+code ALT+code
293 * ---------------------------------------------------------------
294 * F1 0;59 0;84 0;94 0;104
295 * F2 0;60 0;85 0;95 0;105
296 * F3 0;61 0;86 0;96 0;106
297 * F4 0;62 0;87 0;97 0;107
298 * F5 0;63 0;88 0;98 0;108
299 * F6 0;64 0;89 0;99 0;109
300 * F7 0;65 0;90 0;100 0;110
301 * F8 0;66 0;91 0;101 0;111
302 * F9 0;67 0;92 0;102 0;112
303 * F10 0;68 0;93 0;103 0;113
304 * F11 0;133 0;135 0;137 0;139
305 * F12 0;134 0;136 0;138 0;140
306 * HOME (num keypad) 0;71 55 0;119 --
307 * UP ARROW (num keypad) 0;72 56 (0;141) --
308 * PAGE UP (num keypad) 0;73 57 0;132 --
309 * LEFT ARROW (num keypad) 0;75 52 0;115 --
310 * RIGHT ARROW (num keypad) 0;77 54 0;116 --
311 * END (num keypad) 0;79 49 0;117 --
312 * DOWN ARROW (num keypad) 0;80 50 (0;145) --
313 * PAGE DOWN (num keypad) 0;81 51 0;118 --
314 * INSERT (num keypad) 0;82 48 (0;146) --
315 * DELETE (num keypad) 0;83 46 (0;147) --
316 * HOME (224;71) (224;71) (224;119) (224;151)
317 * UP ARROW (224;72) (224;72) (224;141) (224;152)
318 * PAGE UP (224;73) (224;73) (224;132) (224;153)
319 * LEFT ARROW (224;75) (224;75) (224;115) (224;155)
320 * RIGHT ARROW (224;77) (224;77) (224;116) (224;157)
321 * END (224;79) (224;79) (224;117) (224;159)
322 * DOWN ARROW (224;80) (224;80) (224;145) (224;154)
323 * PAGE DOWN (224;81) (224;81) (224;118) (224;161)
324 * INSERT (224;82) (224;82) (224;146) (224;162)
325 * DELETE (224;83) (224;83) (224;147) (224;163)
326 * PRINT SCREEN -- -- 0;114 --
327 * PAUSE/BREAK -- -- 0;0 --
328 * BACKSPACE 8 8 127 (0)
329 * ENTER 13 -- 10 (0
330 * TAB 9 0;15 (0;148) (0;165)
331 * NULL 0;3 -- -- --
332 * A 97 65 1 0;30
333 * B 98 66 2 0;48
334 * C 99 66 3 0;46
335 * D 100 68 4 0;32
336 * E 101 69 5 0;18
337 * F 102 70 6 0;33
338 * G 103 71 7 0;34
339 * H 104 72 8 0;35
340 * I 105 73 9 0;23
341 * J 106 74 10 0;36
342 * K 107 75 11 0;37
343 * L 108 76 12 0;38
344 * M 109 77 13 0;50
345 * N 110 78 14 0;49
346 * O 111 79 15 0;24
347 * P 112 80 16 0;25
348 * Q 113 81 17 0;16
349 * R 114 82 18 0;19
350 * S 115 83 19 0;31
351 * T 116 84 20 0;20
352 * U 117 85 21 0;22
353 * V 118 86 22 0;47
354 * W 119 87 23 0;17
355 * X 120 88 24 0;45
356 * Y 121 89 25 0;21
357 * Z 122 90 26 0;44
358 * 1 49 33 -- 0;120
359 * 2 50 64 0 0;121
360 * 3 51 35 -- 0;122
361 * 4 52 36 -- 0;123
362 * 5 53 37 -- 0;124
363 * 6 54 94 30 0;125
364 * 7 55 38 -- 0;126
365 * 8 56 42 -- 0;126
366 * 9 57 40 -- 0;127
367 * 0 48 41 -- 0;129
368 * - 45 95 31 0;130
369 * = 61 43 --- 0;131
370 * [ 91 123 27 0;26
371 * ] 93 125 29 0;27
372 * 92 124 28 0;43
373 * ; 59 58 -- 0;39
374 * ' 39 34 -- 0;40
375 * , 44 60 -- 0;51
376 * . 46 62 -- 0;52
377 * / 47 63 -- 0;53
378 * ` 96 126 -- (0;41)
379 * ENTER (keypad) 13 -- 10 (0;166)
380 * / (keypad) 47 47 (0;142) (0;74)
381 * * (keypad) 42 (0;144) (0;78) --
382 * - (keypad) 45 45 (0;149) (0;164)
383 * + (keypad) 43 43 (0;150) (0;55)
384 * 5 (keypad) (0;76) 53 (0;143) --
385 */
386 public static String setkey(final String code, final String value) {
387 return ESC + "[" + code + ";" + value + "p";
388 }
389 }
390
391 public static void main(final String[] args) throws Exception {
392 // sequence, one can use: ANSI.setkey ("0;59", "\"Hello F1\";13;10").
393 BufferedReader reader =
394 new BufferedReader(new InputStreamReader(System.in));
395 System.out.print(ANSICodes.setkey("97", "97;98;99;13")
396 + ANSICodes.attrib(ANSICodes.OFF));
397 System.out.flush();
398
399 String line;
400
401 while ((line = reader.readLine()) != null) {
402 System.out.println("GOT: " + line);
403 }
404 }
405 }