package org.infinispan.cli.shell;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Attribute;
/**
* A very simple and incomplete converter from troff-style man macro syntax to ansi
*
* @author Tristan Tarrant
* @since 5.2
*/
public class Man2Ansi {
public static Pattern MAN_MACRO_REGEX = Pattern.compile("^(\\.[A-Z]{1,2} ?)?(.*)$");
public static int DEFAULT_INDENT = 4;
private final Ansi ansi = new Ansi();
private int pos = 0;
private int indent = DEFAULT_INDENT;
private boolean blankLine = true;
private int screenWidth;
public Man2Ansi(int screenWidth) {
this.screenWidth = screenWidth;
}
public String render(InputStream is) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(is));
for (String line = r.readLine(); line != null; line = r.readLine()) {
Matcher matcher = MAN_MACRO_REGEX.matcher(line);
if (matcher.matches()) {
String macro = matcher.group(1);
String text = matcher.group(2);
if (".B ".equals(macro)) {
fit(text, Attribute.INTENSITY_BOLD);
} else if (".I ".equals(macro)) {
fit(text, Attribute.ITALIC);
} else if (".SH ".equals(macro)) {
newline(false);
flushLeft();
newline(true);
fit(text, Attribute.INTENSITY_BOLD);
resetIndent();
newline(true);
} else if (".IP ".equals(macro)) {
resetIndent();
newline(false);
fit(text);
tab(DEFAULT_INDENT);
} else if (".BR".equals(macro)) {
newline(false);
} else {
fit(text);
}
}
}
return ansi.toString();
}
private void newline(boolean force) {
if(force || !blankLine) {
ansi.newline();
indent();
}
}
private void fit(String text, Attribute... attributes) {
if (pos + text.length() > screenWidth) {
int ideal = screenWidth-pos;
int actual = text.lastIndexOf(' ', ideal);
if (actual>0) {
format(text.substring(0, actual));
ansi.newline();
indent();
fit(text.substring(actual+1), attributes);
return;
} else {
ansi.newline();
indent();
}
}
format(text, attributes);
if (text.length() > 0 && text.charAt(text.length()-1) != ' ')
format(" ", attributes);
pos += text.length();
blankLine = false;
}
private void format(String text, Attribute... attributes) {
for (Attribute attribute : attributes) {
ansi.a(attribute);
}
ansi.render(text).reset();
}
private void tab(int add) {
indent += add;
if (pos>=indent) {
newline(false);
} else {
for(; pos<indent; pos++) {
ansi.render(" ");
}
}
}
private void indent() {
indent(0);
}
private void indent(int add) {
indent += add;
for (int i = 0; i < indent; i++) {
ansi.render(" ");
}
pos = indent;
blankLine = true;
}
private void resetIndent() {
indent = DEFAULT_INDENT;
}
private void flushLeft() {
indent = 0;
}
}