jlibs.core.lang.Ansi Maven / Gradle / Ivy
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license 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 jlibs.core.lang;
import java.io.PrintStream;
/**
* Ansi coloring support is provided by this class.
*
* To print "hello ansi world" in bold with blue foreground and white background:
*
* Ansi ansi = new Ansi(Ansi.Attribute.BRIGHT, Ansi.Color.BLUE, Ansi.Color.WHITE);
* ansi.{@link #out(String) out}("hello ansi world")
*
*
* same can be done as below:
*
* String msg = ansi.{@link #colorize(String) colorize}("hello ansi world"); // msg is original string wrapped with ansi control sequences
* System.out.println(msg);
*
*
* Ansi Support:
*
* Ansi might not be supported on all systems. Ansi is mostly supported by all unix operating systems.
*
* {@link Ansi#SUPPORTED} is a final boolean, that can be used to check whether your console supports Ansi format;
*
* Ansi class uses simple checks to decide whether ansi is supported or not. Sometimes it may do wrong guess.
* In such cases you can override its decision using following system property:
* -DAnsi=true
or -DAnsi=false
*
* if {@link Ansi#SUPPORTED} is false, any ansi method will not produce ansi control sequences. so you can safely use:
* ansi.out("hello ansi world")
irrespective of ansi is supported or not.
* if ansi is not supported, this will simply do System.out.print("hello ansi world")
*
* @see jlibs.core.util.logging.AnsiFormatter
*
* @author Santhosh Kumar T
*/
public class Ansi{
/**
* specifies whether ansi is supported or not.
*
* when this is false, it doesn't colorize given strings, rather than
* simply returns the given strings
*
* It tries best effort to guess whether ansi is supported or not. But
* you can override this value using system property "Ansi" (-DAnsi=true/false)
*/
public static final boolean SUPPORTED = Boolean.getBoolean("Ansi") || (OS.get().isUnix() && System.console()!=null);
/** this enum represents the attribute of text */
public enum Attribute{
/** Reset All Attributes (return to normal mode) */
NORMAL(0),
/** Usually turns on BOLD */
BRIGHT(1),
DIM(2),
UNDERLINE(4),
BLINK(5),
/** Reverse video on */
REVERSE(7),
/** Concealed on */
HIDDEN(8);
private String value;
private Attribute(int value){
this.value = String.valueOf(value);
}
public String toString(){
return ""+value;
}
}
/** this enum represents the color of text */
public enum Color{ BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }
private static final String PREFIX = "\u001b["; //NOI18N
private static final String SUFFIX = "m";
private static final String SEPARATOR = ";";
private static final String END = PREFIX + SUFFIX;
private String start = "";
/**
* Creates new instanceof Ansi.
*
* @param attr attribute of text, null means don't change
* @param foreground foreground color of text, null means don't change
* @param background background color of text, null means don't change
*/
public Ansi(Attribute attr, Color foreground, Color background){
init(attr, foreground, background);
}
/**
* Creates new instanceof of ansi with specified format.
* The format syntax is
*
* Attribute[;Foreground[;Background]]
*
* i.e, semicolon(;) separated values, where tokens are attribute, foreground and background respectively.
* if any non-trailing token in value is null, you still need to specify empty value. for example:
*
* DIM;;GREEN # foreground is not specified
*
*
* @param format
*/
public Ansi(String format){
String tokens[] = format.split(";");
Ansi.Attribute attribute = null;
try{
if(tokens.length>0 && tokens[0].length()>0)
attribute = Ansi.Attribute.valueOf(tokens[0]);
}catch(IllegalArgumentException ex){
ex.printStackTrace();
}
Ansi.Color foreground = null;
try{
if(tokens.length>1 && tokens[1].length()>0)
foreground = Ansi.Color.valueOf(tokens[1]);
}catch(IllegalArgumentException e){
e.printStackTrace();
}
Ansi.Color background = null;
try{
if(tokens.length>2 && tokens[2].length()>0)
background = Ansi.Color.valueOf(tokens[2]);
}catch(IllegalArgumentException e){
e.printStackTrace();
}
init(attribute, foreground, background);
}
private void init(Attribute attr, Color foreground, Color background){
StringBuilder buff = new StringBuilder();
if(attr!=null)
buff.append(attr);
if(foreground!=null){
if(buff.length()>0)
buff.append(SEPARATOR);
buff.append(30+foreground.ordinal());
}
if(background!=null){
if(buff.length()>0)
buff.append(SEPARATOR);
buff.append(40+background.ordinal());
}
buff.insert(0, PREFIX);
buff.append(SUFFIX);
start = buff.toString();
}
/**
* The string representation of this object. This string will be the same that is
* expected by {@link #Ansi(String)}
*
* @return string representation of this object
*/
@Override
public String toString(){
Attribute attr = null;
Color foreground = null;
Color background = null;
for(String token: start.substring(PREFIX.length(), start.length()-SUFFIX.length()).split(SEPARATOR)){
int i = Integer.parseInt(token);
if(i<30){
for(Attribute value: Attribute.values()){
if(value.toString().equals(token)){
attr = value;
break;
}
}
}else if(i<40)
foreground = Color.values()[i-30];
else
background = Color.values()[i-40];
}
StringBuilder buff = new StringBuilder();
if(attr!=null)
buff.append(attr.name());
buff.append(';');
if(foreground!=null)
buff.append(foreground.name());
buff.append(';');
if(background!=null)
buff.append(background.name());
int end = buff.length()-1;
while(end>=0 && buff.charAt(end)==';')
end--;
return buff.substring(0, end+1);
}
/** Wrapps given message with special ansi control sequences and returns it */
public String colorize(String message){
if(SUPPORTED){
StringBuilder buff = new StringBuilder(start.length()+message.length()+END.length());
buff.append(start).append(message).append(END);
return buff.toString();
}else
return message;
}
/*-------------------------------------------------[ Printing ]---------------------------------------------------*/
/**
* Prints colorized {@code message} to specified {@code ps}.
*
* if {@link #SUPPORTED} is false, it prints raw {@code message} to {@code ps}
*
* @param ps stream to print
* @param message message to be colorized
*/
public void print(PrintStream ps, String message){
if(SUPPORTED)
ps.print(start);
ps.print(message);
if(SUPPORTED)
ps.print(END);
}
/**
* Prints colorized {@code message} to specified {@code ps} followed by newline.
*
* if {@link #SUPPORTED} is false, it prints raw {@code message} to {@code ps} followed by newline.
*
* @param ps stream to print
* @param message message to be colorized
*/
public void println(PrintStream ps, String message){
print(ps, message);
ps.println();
}
/**
* Prints formatted and colorized {@code message} to specified {@code ps}.
*
* if {@link #SUPPORTED} is false, it prints formatted {@code message} to {@code ps}
*
* @param ps stream to print
* @param format A format string whose output to be colorized
* @param args Arguments referenced by the format specifiers in the format
*/
public void format(PrintStream ps, String format, Object... args){
if(SUPPORTED)
ps.print(start);
ps.format(format, args);
if(SUPPORTED)
ps.print(END);
}
/*-------------------------------------------------[ System.out ]---------------------------------------------------*/
/**
* Prints colorized {@code message} to {@link System#out}
*
* @param message message to be colorized
*/
public void out(String message){
print(System.out, message);
}
/**
* Prints colorized {@code message} to {@link System#out} followed by newline
*
* @param message message to be colorized
*/
public void outln(String message){
println(System.out, message);
}
/**
* Prints formatted and colorized {@code format} to {@link System#out}
*
* @param format A format string whose output to be colorized
* @param args Arguments referenced by the format specifiers in the format
*/
public void outFormat(String format, Object... args){
format(System.out, format, args);
}
/*-------------------------------------------------[ System.err ]---------------------------------------------------*/
/**
* Prints colorized {@code message} to {@link System#err}
*
* @param message message to be colorized
*/
public void err(String message){
print(System.err, message);
}
/**
* Prints colorized {@code message} to {@link System#err} followed by newline
*
* @param message message to be colorized
*/
public void errln(String message){
print(System.err, message);
}
/**
* Prints formatted and colorized {@code format} to {@link System#err}
*
* @param format A format string whose output to be colorized
* @param args Arguments referenced by the format specifiers in the format
*/
public void errFormat(String format, Object... args){
format(System.err, format, args);
}
}