compat/maven-embedder/src/main/java/org/fusesource/jansi/Ansi.java (655 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.fusesource.jansi; import java.util.ArrayList; /** * Provides a fluent API for generating * <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences">ANSI escape sequences</a>. * * This class comes from Jansi and is provided for backward compatibility * with maven-shared-utils, while Maven has migrated to JLine (into which Jansi has been merged * since JLine 3.25.0). */ @Deprecated @SuppressWarnings("unused") public class Ansi implements Appendable { private static final char FIRST_ESC_CHAR = 27; private static final char SECOND_ESC_CHAR = '['; /** * <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">ANSI 8 colors</a> for fluent API */ public enum Color { BLACK(0, "BLACK"), RED(1, "RED"), GREEN(2, "GREEN"), YELLOW(3, "YELLOW"), BLUE(4, "BLUE"), MAGENTA(5, "MAGENTA"), CYAN(6, "CYAN"), WHITE(7, "WHITE"), DEFAULT(9, "DEFAULT"); private final int value; private final String name; Color(int index, String name) { this.value = index; this.name = name; } @Override public String toString() { return name; } public int value() { return value; } public int fg() { return value + 30; } public int bg() { return value + 40; } public int fgBright() { return value + 90; } public int bgBright() { return value + 100; } } /** * Display attributes, also known as * <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters">SGR * (Select Graphic Rendition) parameters</a>. */ public enum Attribute { RESET(0, "RESET"), INTENSITY_BOLD(1, "INTENSITY_BOLD"), INTENSITY_FAINT(2, "INTENSITY_FAINT"), ITALIC(3, "ITALIC_ON"), UNDERLINE(4, "UNDERLINE_ON"), BLINK_SLOW(5, "BLINK_SLOW"), BLINK_FAST(6, "BLINK_FAST"), NEGATIVE_ON(7, "NEGATIVE_ON"), CONCEAL_ON(8, "CONCEAL_ON"), STRIKETHROUGH_ON(9, "STRIKETHROUGH_ON"), UNDERLINE_DOUBLE(21, "UNDERLINE_DOUBLE"), INTENSITY_BOLD_OFF(22, "INTENSITY_BOLD_OFF"), ITALIC_OFF(23, "ITALIC_OFF"), UNDERLINE_OFF(24, "UNDERLINE_OFF"), BLINK_OFF(25, "BLINK_OFF"), NEGATIVE_OFF(27, "NEGATIVE_OFF"), CONCEAL_OFF(28, "CONCEAL_OFF"), STRIKETHROUGH_OFF(29, "STRIKETHROUGH_OFF"); private final int value; private final String name; Attribute(int index, String name) { this.value = index; this.name = name; } @Override public String toString() { return name; } public int value() { return value; } } /** * ED (Erase in Display) / EL (Erase in Line) parameter (see * <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences">CSI sequence J and K</a>) * @see Ansi#eraseScreen(Erase) * @see Ansi#eraseLine(Erase) */ public enum Erase { FORWARD(0, "FORWARD"), BACKWARD(1, "BACKWARD"), ALL(2, "ALL"); private final int value; private final String name; Erase(int index, String name) { this.value = index; this.name = name; } @Override public String toString() { return name; } public int value() { return value; } } @FunctionalInterface public interface Consumer { void apply(Ansi ansi); } public static boolean isEnabled() { return org.apache.maven.jline.MessageUtils.isColorEnabled() && org.jline.jansi.Ansi.isEnabled(); } public static void setEnabled(final boolean flag) { org.jline.jansi.Ansi.setEnabled(flag); } public static Ansi ansi() { if (isEnabled()) { return new Ansi(); } else { return new NoAnsi(); } } public static Ansi ansi(StringBuilder builder) { if (isEnabled()) { return new Ansi(builder); } else { return new NoAnsi(builder); } } public static Ansi ansi(int size) { if (isEnabled()) { return new Ansi(size); } else { return new NoAnsi(size); } } private static class NoAnsi extends Ansi { NoAnsi() { super(); } NoAnsi(int size) { super(size); } NoAnsi(StringBuilder builder) { super(builder); } @Override public Ansi fg(Color color) { return this; } @Override public Ansi bg(Color color) { return this; } @Override public Ansi fgBright(Color color) { return this; } @Override public Ansi bgBright(Color color) { return this; } @Override public Ansi fg(int color) { return this; } @Override public Ansi fgRgb(int r, int g, int b) { return this; } @Override public Ansi bg(int color) { return this; } @Override public Ansi bgRgb(int r, int g, int b) { return this; } @Override public Ansi a(Attribute attribute) { return this; } @Override public Ansi cursor(int row, int column) { return this; } @Override public Ansi cursorToColumn(int x) { return this; } @Override public Ansi cursorUp(int y) { return this; } @Override public Ansi cursorRight(int x) { return this; } @Override public Ansi cursorDown(int y) { return this; } @Override public Ansi cursorLeft(int x) { return this; } @Override public Ansi cursorDownLine() { return this; } @Override public Ansi cursorDownLine(final int n) { return this; } @Override public Ansi cursorUpLine() { return this; } @Override public Ansi cursorUpLine(final int n) { return this; } @Override public Ansi eraseScreen() { return this; } @Override public Ansi eraseScreen(Erase kind) { return this; } @Override public Ansi eraseLine() { return this; } @Override public Ansi eraseLine(Erase kind) { return this; } @Override public Ansi scrollUp(int rows) { return this; } @Override public Ansi scrollDown(int rows) { return this; } @Override public Ansi saveCursorPosition() { return this; } @Override @Deprecated public Ansi restorCursorPosition() { return this; } @Override public Ansi restoreCursorPosition() { return this; } @Override public Ansi reset() { return this; } } private final StringBuilder builder; private final ArrayList<Integer> attributeOptions = new ArrayList<>(5); public Ansi() { this(new StringBuilder(80)); } public Ansi(Ansi parent) { this(new StringBuilder(parent.builder)); attributeOptions.addAll(parent.attributeOptions); } public Ansi(int size) { this(new StringBuilder(size)); } public Ansi(StringBuilder builder) { this.builder = builder; } public Ansi fg(Color color) { attributeOptions.add(color.fg()); return this; } public Ansi fg(int color) { attributeOptions.add(38); attributeOptions.add(5); attributeOptions.add(color & 0xff); return this; } public Ansi fgRgb(int color) { return fgRgb(color >> 16, color >> 8, color); } public Ansi fgRgb(int r, int g, int b) { attributeOptions.add(38); attributeOptions.add(2); attributeOptions.add(r & 0xff); attributeOptions.add(g & 0xff); attributeOptions.add(b & 0xff); return this; } public Ansi fgBlack() { return this.fg(Color.BLACK); } public Ansi fgBlue() { return this.fg(Color.BLUE); } public Ansi fgCyan() { return this.fg(Color.CYAN); } public Ansi fgDefault() { return this.fg(Color.DEFAULT); } public Ansi fgGreen() { return this.fg(Color.GREEN); } public Ansi fgMagenta() { return this.fg(Color.MAGENTA); } public Ansi fgRed() { return this.fg(Color.RED); } public Ansi fgYellow() { return this.fg(Color.YELLOW); } public Ansi bg(Color color) { attributeOptions.add(color.bg()); return this; } public Ansi bg(int color) { attributeOptions.add(48); attributeOptions.add(5); attributeOptions.add(color & 0xff); return this; } public Ansi bgRgb(int color) { return bgRgb(color >> 16, color >> 8, color); } public Ansi bgRgb(int r, int g, int b) { attributeOptions.add(48); attributeOptions.add(2); attributeOptions.add(r & 0xff); attributeOptions.add(g & 0xff); attributeOptions.add(b & 0xff); return this; } public Ansi bgCyan() { return this.bg(Color.CYAN); } public Ansi bgDefault() { return this.bg(Color.DEFAULT); } public Ansi bgGreen() { return this.bg(Color.GREEN); } public Ansi bgMagenta() { return this.bg(Color.MAGENTA); } public Ansi bgRed() { return this.bg(Color.RED); } public Ansi bgYellow() { return this.bg(Color.YELLOW); } public Ansi fgBright(Color color) { attributeOptions.add(color.fgBright()); return this; } public Ansi fgBrightBlack() { return this.fgBright(Color.BLACK); } public Ansi fgBrightBlue() { return this.fgBright(Color.BLUE); } public Ansi fgBrightCyan() { return this.fgBright(Color.CYAN); } public Ansi fgBrightDefault() { return this.fgBright(Color.DEFAULT); } public Ansi fgBrightGreen() { return this.fgBright(Color.GREEN); } public Ansi fgBrightMagenta() { return this.fgBright(Color.MAGENTA); } public Ansi fgBrightRed() { return this.fgBright(Color.RED); } public Ansi fgBrightYellow() { return this.fgBright(Color.YELLOW); } public Ansi bgBright(Color color) { attributeOptions.add(color.bgBright()); return this; } public Ansi bgBrightCyan() { return this.bgBright(Color.CYAN); } public Ansi bgBrightDefault() { return this.bgBright(Color.DEFAULT); } public Ansi bgBrightGreen() { return this.bgBright(Color.GREEN); } public Ansi bgBrightMagenta() { return this.bgBright(Color.MAGENTA); } public Ansi bgBrightRed() { return this.bgBright(Color.RED); } public Ansi bgBrightYellow() { return this.bgBright(Color.YELLOW); } public Ansi a(Attribute attribute) { attributeOptions.add(attribute.value()); return this; } /** * Moves the cursor to row n, column m. The values are 1-based. * Any values less than 1 are mapped to 1. * * @param row row (1-based) from top * @param column column (1 based) from left * @return this Ansi instance */ public Ansi cursor(final int row, final int column) { return appendEscapeSequence('H', Math.max(1, row), Math.max(1, column)); } /** * Moves the cursor to column n. The parameter n is 1-based. * If n is less than 1 it is moved to the first column. * * @param x the index (1-based) of the column to move to * @return this Ansi instance */ public Ansi cursorToColumn(final int x) { return appendEscapeSequence('G', Math.max(1, x)); } /** * Moves the cursor up. If the parameter y is negative it moves the cursor down. * * @param y the number of lines to move up * @return this Ansi instance */ public Ansi cursorUp(final int y) { return y > 0 ? appendEscapeSequence('A', y) : y < 0 ? cursorDown(-y) : this; } /** * Moves the cursor down. If the parameter y is negative it moves the cursor up. * * @param y the number of lines to move down * @return this Ansi instance */ public Ansi cursorDown(final int y) { return y > 0 ? appendEscapeSequence('B', y) : y < 0 ? cursorUp(-y) : this; } /** * Moves the cursor right. If the parameter x is negative it moves the cursor left. * * @param x the number of characters to move right * @return this Ansi instance */ public Ansi cursorRight(final int x) { return x > 0 ? appendEscapeSequence('C', x) : x < 0 ? cursorLeft(-x) : this; } /** * Moves the cursor left. If the parameter x is negative it moves the cursor right. * * @param x the number of characters to move left * @return this Ansi instance */ public Ansi cursorLeft(final int x) { return x > 0 ? appendEscapeSequence('D', x) : x < 0 ? cursorRight(-x) : this; } /** * Moves the cursor relative to the current position. The cursor is moved right if x is * positive, left if negative and down if y is positive and up if negative. * * @param x the number of characters to move horizontally * @param y the number of lines to move vertically * @return this Ansi instance * @since 2.2 */ public Ansi cursorMove(final int x, final int y) { return cursorRight(x).cursorDown(y); } /** * Moves the cursor to the beginning of the line below. * * @return this Ansi instance */ public Ansi cursorDownLine() { return appendEscapeSequence('E'); } /** * Moves the cursor to the beginning of the n-th line below. If the parameter n is negative it * moves the cursor to the beginning of the n-th line above. * * @param n the number of lines to move the cursor * @return this Ansi instance */ public Ansi cursorDownLine(final int n) { return n < 0 ? cursorUpLine(-n) : appendEscapeSequence('E', n); } /** * Moves the cursor to the beginning of the line above. * * @return this Ansi instance */ public Ansi cursorUpLine() { return appendEscapeSequence('F'); } /** * Moves the cursor to the beginning of the n-th line above. If the parameter n is negative it * moves the cursor to the beginning of the n-th line below. * * @param n the number of lines to move the cursor * @return this Ansi instance */ public Ansi cursorUpLine(final int n) { return n < 0 ? cursorDownLine(-n) : appendEscapeSequence('F', n); } public Ansi eraseScreen() { return appendEscapeSequence('J', Erase.ALL.value()); } public Ansi eraseScreen(final Erase kind) { return appendEscapeSequence('J', kind.value()); } public Ansi eraseLine() { return appendEscapeSequence('K'); } public Ansi eraseLine(final Erase kind) { return appendEscapeSequence('K', kind.value()); } public Ansi scrollUp(final int rows) { if (rows == Integer.MIN_VALUE) { return scrollDown(Integer.MAX_VALUE); } return rows > 0 ? appendEscapeSequence('S', rows) : rows < 0 ? scrollDown(-rows) : this; } public Ansi scrollDown(final int rows) { if (rows == Integer.MIN_VALUE) { return scrollUp(Integer.MAX_VALUE); } return rows > 0 ? appendEscapeSequence('T', rows) : rows < 0 ? scrollUp(-rows) : this; } @Deprecated public Ansi restorCursorPosition() { return restoreCursorPosition(); } public Ansi saveCursorPosition() { saveCursorPositionSCO(); return saveCursorPositionDEC(); } // SCO command public Ansi saveCursorPositionSCO() { return appendEscapeSequence('s'); } // DEC command public Ansi saveCursorPositionDEC() { builder.append(FIRST_ESC_CHAR); builder.append('7'); return this; } public Ansi restoreCursorPosition() { restoreCursorPositionSCO(); return restoreCursorPositionDEC(); } // SCO command public Ansi restoreCursorPositionSCO() { return appendEscapeSequence('u'); } // DEC command public Ansi restoreCursorPositionDEC() { builder.append(FIRST_ESC_CHAR); builder.append('8'); return this; } public Ansi reset() { return a(Attribute.RESET); } public Ansi bold() { return a(Attribute.INTENSITY_BOLD); } public Ansi boldOff() { return a(Attribute.INTENSITY_BOLD_OFF); } public Ansi a(String value) { flushAttributes(); builder.append(value); return this; } public Ansi a(boolean value) { flushAttributes(); builder.append(value); return this; } public Ansi a(char value) { flushAttributes(); builder.append(value); return this; } public Ansi a(char[] value, int offset, int len) { flushAttributes(); builder.append(value, offset, len); return this; } public Ansi a(char[] value) { flushAttributes(); builder.append(value); return this; } public Ansi a(CharSequence value, int start, int end) { flushAttributes(); builder.append(value, start, end); return this; } public Ansi a(CharSequence value) { flushAttributes(); builder.append(value); return this; } public Ansi a(double value) { flushAttributes(); builder.append(value); return this; } public Ansi a(float value) { flushAttributes(); builder.append(value); return this; } public Ansi a(int value) { flushAttributes(); builder.append(value); return this; } public Ansi a(long value) { flushAttributes(); builder.append(value); return this; } public Ansi a(Object value) { flushAttributes(); builder.append(value); return this; } public Ansi a(StringBuffer value) { flushAttributes(); builder.append(value); return this; } public Ansi newline() { flushAttributes(); builder.append(System.lineSeparator()); return this; } public Ansi format(String pattern, Object... args) { flushAttributes(); builder.append(String.format(pattern, args)); return this; } /** * Applies another function to this Ansi instance. * * @param fun the function to apply * @return this Ansi instance * @since 2.2 */ public Ansi apply(Consumer fun) { fun.apply(this); return this; } /** * Uses the {@link org.jline.jansi.AnsiRenderer} * to generate the ANSI escape sequences for the supplied text. * * @param text text * @return this * @since 2.2 */ public Ansi render(final String text) { a(new org.jline.jansi.Ansi().render(text).toString()); return this; } /** * String formats and renders the supplied arguments. Uses the {@link org.jline.jansi.AnsiRenderer} * to generate the ANSI escape sequences. * * @param text format * @param args arguments * @return this * @since 2.2 */ public Ansi render(final String text, Object... args) { a(String.format(new org.jline.jansi.Ansi().render(text).toString(), args)); return this; } @Override public String toString() { flushAttributes(); return builder.toString(); } /////////////////////////////////////////////////////////////////// // Private Helper Methods /////////////////////////////////////////////////////////////////// private Ansi appendEscapeSequence(char command) { flushAttributes(); builder.append(FIRST_ESC_CHAR); builder.append(SECOND_ESC_CHAR); builder.append(command); return this; } private Ansi appendEscapeSequence(char command, int option) { flushAttributes(); builder.append(FIRST_ESC_CHAR); builder.append(SECOND_ESC_CHAR); builder.append(option); builder.append(command); return this; } private Ansi appendEscapeSequence(char command, Object... options) { flushAttributes(); return doAppendEscapeSequence(command, options); } private void flushAttributes() { if (attributeOptions.isEmpty()) { return; } if (attributeOptions.size() == 1 && attributeOptions.get(0) == 0) { builder.append(FIRST_ESC_CHAR); builder.append(SECOND_ESC_CHAR); builder.append('m'); } else { doAppendEscapeSequence('m', attributeOptions.toArray()); } attributeOptions.clear(); } private Ansi doAppendEscapeSequence(char command, Object... options) { builder.append(FIRST_ESC_CHAR); builder.append(SECOND_ESC_CHAR); int size = options.length; for (int i = 0; i < size; i++) { if (i != 0) { builder.append(';'); } if (options[i] != null) { builder.append(options[i]); } } builder.append(command); return this; } @Override public Ansi append(CharSequence csq) { builder.append(csq); return this; } @Override public Ansi append(CharSequence csq, int start, int end) { builder.append(csq, start, end); return this; } @Override public Ansi append(char c) { builder.append(c); return this; } }