Update SubServers.Console

This commit is contained in:
ME1312 2021-06-12 23:20:41 -04:00
parent de0e9a676d
commit 910b504af8
No known key found for this signature in database
GPG Key ID: FEFFE2F698E88FA8
6 changed files with 295 additions and 206 deletions

View File

@ -18,8 +18,8 @@
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.17.1</version>
<scope>provided</scope>
<version>1.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.intellij</groupId>

View File

@ -1,4 +1,4 @@
name: SubServers-Console
main: net.ME1312.SubServers.Console.ConsolePlugin
version: 2.16a
version: 2.17a
author: ME1312

View File

@ -5,6 +5,7 @@ import net.ME1312.SubServers.Bungee.Event.SubCreateEvent;
import net.ME1312.SubServers.Bungee.Event.SubSendCommandEvent;
import net.ME1312.SubServers.Bungee.Event.SubStartEvent;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.RemotePlayer;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.SubAPI;
@ -19,6 +20,7 @@ import net.md_5.bungee.event.EventPriority;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
@ -103,7 +105,8 @@ public final class ConsolePlugin extends Plugin implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onServerCommand(SubSendCommandEvent event) {
if (!event.isCancelled() && sCurrent.keySet().contains(event.getServer().getName().toLowerCase())) {
sCurrent.get(event.getServer().getName().toLowerCase()).log('<' + ((event.getPlayer() == null)?"CONSOLE":((getProxy().getPlayer(event.getPlayer()) == null)?event.getPlayer().toString():getProxy().getPlayer(event.getPlayer()).getName())) + "> /" + event.getCommand());
RemotePlayer player = (event.getPlayer() == null)? null : SubAPI.getInstance().getRemotePlayer(event.getPlayer());
sCurrent.get(event.getServer().getName().toLowerCase()).log(((player == null)? "CONSOLE" : player.getName()) + "> /" + event.getCommand());
}
}

View File

@ -24,11 +24,15 @@ import java.io.*;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import static java.nio.charset.StandardCharsets.UTF_8;
public final class ConsoleWindow implements SubLogFilter {
private static final int MAX_SCROLLBACK = (Integer.getInteger("subservers.console.max_scrollback", 0) >= 128)?Integer.getInteger("subservers.console.max_scrollback"):7500;
private static final String RESET_VALUE = "\n\u00A0\n\u00A0";
private static final int MAX_SCROLLBACK = (Integer.getInteger("subservers.console.max_scrollback", 0) > 0)?Integer.getInteger("subservers.console.max_scrollback"):7500;
private ConsolePlugin plugin;
private JFrame window;
private double scale = 1.0;
@ -48,53 +52,56 @@ public final class ConsoleWindow implements SubLogFilter {
private int findO = 0;
private int findI = 0;
private boolean open = false;
private boolean running = true;
private LinkedList<Object> messages = new LinkedList<Object>();
private ExecutorService thread;
private SubLogger logger;
private int fontSize;
private File file = null;
private FileOutputStream filewriter = null;
private List<Runnable> spost = new LinkedList<Runnable>();
private ByteArrayOutputStream scache = new ByteArrayOutputStream();
private AnsiUIOutputStream stream = AnsiUIOutputStream.wrap(new OutputStream() {
private long sbytes = -Long.MAX_VALUE;
private LinkedList<Long> slines = new LinkedList<Long>();
private LinkedList<Runnable> spost = new LinkedList<Runnable>();
private AnsiUIOutputStream stream = HTMLogger.wrap(new OutputStream() {
private final ByteArrayOutputStream scache = new ByteArrayOutputStream();
private int countLines(String str) {
int count = 0;
for (int i = 0; i < str.length(); i++) if (str.charAt(i) == '\n') count++;
for (int i = 1; i < str.codePoints().count(); i++) if (str.codePointAt(i) == '\n') count++;
return count;
}
@Override
public void write(int b) throws IOException {
scache.write(b);
if (b == '\n') {
try {
HTMLEditorKit kit = (HTMLEditorKit) log.getEditorKit();
HTMLDocument doc = (HTMLDocument) log.getDocument();
kit.insertHTML(doc, doc.getLength() - 2, new String(scache.toByteArray(), "UTF-8"), 0, 0, null);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
hScroll();
}
});
} catch (Exception e) {} try {
int lines;
String content;
if (log.getSelectionStart() == log.getSelectionEnd() && (lines = countLines(content = log.getDocument().getText(0, log.getDocument().getLength()))) > MAX_SCROLLBACK + 2) {
int lineBreak = 1;
for (lines -= MAX_SCROLLBACK; lines > 0; lines--) lineBreak = content.indexOf('\n', lineBreak + 1);
if (lineBreak <= log.getDocument().getLength() - 2 && log.getSelectionStart() == log.getSelectionEnd()) {
log.getDocument().remove(0, lineBreak);
}
}
@Override
public void flush() throws IOException {
try {
HTMLDocument doc = (HTMLDocument) log.getDocument();
((HTMLEditorKit) log.getEditorKit()).insertHTML(doc, doc.getLength() - 2, new String(scache.toByteArray(), UTF_8), 0, 0, null);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
hScroll();
}
} catch (Exception e) {}
for (Runnable post : spost) try {
post.run();
} catch (Throwable e) {}
spost.clear();
scache = new ByteArrayOutputStream();
}
});
} catch (Exception e) {} try {
int lines;
String content;
HTMLDocument doc = (HTMLDocument) log.getDocument();
if (log.getSelectionStart() == log.getSelectionEnd() && (lines = countLines(content = doc.getText(2, doc.getLength() - 2))) > MAX_SCROLLBACK) {
int lfl = 0;
for (lines -= MAX_SCROLLBACK; lines > 0; --lines) lfl = content.indexOf('\n', lfl + 1);
if (log.getSelectionStart() == log.getSelectionEnd()) {
doc.remove(2, lfl);
}
}
} catch (Exception e) {}
for (Runnable post : spost) try {
post.run();
} catch (Throwable e) {}
spost.clear();
scache.reset();
}
}, new HTMLogger.HTMConstructor<AnsiUIOutputStream>() {
@Override
@ -193,6 +200,7 @@ public final class ConsoleWindow implements SubLogFilter {
@Override
public void actionPerformed(ActionEvent event) {
ConsoleWindow.this.clear();
ConsoleWindow.this.hScroll();
}
});
menu.add(item);
@ -201,8 +209,9 @@ public final class ConsoleWindow implements SubLogFilter {
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
log.setText(RESET_VALUE);
ConsoleWindow.this.clear();
ConsoleWindow.this.loadContent();
ConsoleWindow.this.hScroll();
}
});
menu.add(item);
@ -315,8 +324,9 @@ public final class ConsoleWindow implements SubLogFilter {
@Override
public void actionPerformed(ActionEvent event) {
stream.ansi(((AbstractButton) event.getSource()).getModel().isSelected());
log.setText(RESET_VALUE);
ConsoleWindow.this.clear();
ConsoleWindow.this.loadContent();
ConsoleWindow.this.hScroll();
}
});
menu.add(item);
@ -325,7 +335,7 @@ public final class ConsoleWindow implements SubLogFilter {
@Override
public void actionPerformed(ActionEvent event) {
HTMLDocument doc = (HTMLDocument) log.getDocument();
fontSize = (int) (12 * scale);
fontSize = (int) (13 * scale);
doc.getStyleSheet().addRule("body {font-size: " + fontSize + ";}\n");
ConsoleWindow.this.hScroll();
}
@ -337,7 +347,7 @@ public final class ConsoleWindow implements SubLogFilter {
@Override
public void actionPerformed(ActionEvent event) {
HTMLDocument doc = (HTMLDocument) log.getDocument();
fontSize += 2 * scale;
fontSize += scale;
doc.getStyleSheet().addRule("body {font-size: " + fontSize + ";}\n");
ConsoleWindow.this.hScroll();
}
@ -349,7 +359,7 @@ public final class ConsoleWindow implements SubLogFilter {
@Override
public void actionPerformed(ActionEvent event) {
HTMLDocument doc = (HTMLDocument) log.getDocument();
fontSize -= 2 * scale;
fontSize -= scale;
doc.getStyleSheet().addRule("body {font-size: " + fontSize + ";}\n");
ConsoleWindow.this.hScroll();
}
@ -367,11 +377,10 @@ public final class ConsoleWindow implements SubLogFilter {
}
});
window.setTitle(logger.getName() + " \u2014 SubServers 2");
window.setSize(1024, 576);
window.setSize((int) (1024 * scale), (int) (576 * scale));
window.setSize((int) (1280 * scale), (int) (720 * scale));
window.setLocation(
(int) ((screen.getWidth() - window.getWidth()) / 2),
(int) ((screen.getHeight() - window.getHeight()) / 2)
(int) Math.abs((screen.getWidth() - window.getWidth()) / 2),
(int) Math.abs((screen.getHeight() - window.getHeight()) / 2)
);
window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
window.addWindowListener(new WindowAdapter() {
@ -391,13 +400,13 @@ public final class ConsoleWindow implements SubLogFilter {
log.setContentType("text/html");
log.setEditorKit(new HTMLEditorKit());
StyleSheet style = new StyleSheet();
fontSize = (int) (12 * scale);
fontSize = (int) (13 * scale);
String font;
try {
Font f = Font.createFont(Font.TRUETYPE_FONT, ConsoleWindow.class.getResourceAsStream("/net/ME1312/SubServers/Console/ConsoleFont.ttf"));
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(f);
font = f.getFontName();
input.setFont(f.deriveFont((float) (14 * scale)));
input.setFont(f);
} catch (Exception e) {
font = "Courier";
}
@ -447,11 +456,13 @@ public final class ConsoleWindow implements SubLogFilter {
if (offset < 1) {
return;
}
string = string.replace("\n", "\\n");
super.insertString(fb, offset, string, attr);
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
text = text.replace("\n", "\\n");
if (offset < 1) {
length = Math.max(0, length - 1);
offset = input.getDocument().getLength();
@ -552,7 +563,6 @@ public final class ConsoleWindow implements SubLogFilter {
}
});
findP.setBorder(new ButtonBorder(40, 44, 45, (int) (4 * scale)));
findN.setFont(findN.getFont().deriveFont((float) (findN.getFont().getSize() * scale)));
findP.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
@ -567,6 +577,7 @@ public final class ConsoleWindow implements SubLogFilter {
}
});
findN.setBorder(new ButtonBorder(40, 44, 45, (int) (4 * scale)));
findN.setFont(findN.getFont().deriveFont((float) (findN.getFont().getSize() * scale)));
findN.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
@ -600,32 +611,116 @@ public final class ConsoleWindow implements SubLogFilter {
vScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
thread = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "SubServers.Console::Log_Spooler(" + logger.getName() + ")");
}
});
try {
clear();
slines.add(sbytes);
stream.write("\u00A0".getBytes(UTF_8));
} catch (IOException e) {}
logger.registerFilter(this);
log.setText(RESET_VALUE);
loadContent();
log();
hScroll();
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keys);
}
private void hScroll() {
hScroll.setMaximum(vScroll.getHorizontalScrollBar().getMaximum());
hScroll.setMinimum(vScroll.getHorizontalScrollBar().getMinimum());
hScroll.setVisibleAmount(vScroll.getHorizontalScrollBar().getVisibleAmount());
hScroll.setVisible(input.isVisible() && hScroll.getVisibleAmount() < hScroll.getMaximum());
@Override
public void start() {}
public void open() {
if (!open) {
window.setVisible(true);
this.open = true;
}
window.toFront();
}
public SubLogger getLogger() {
return logger;
private void loadContent() {
this.sbytes = (slines.size() > 0) ? slines.getFirst() : -Long.MAX_VALUE;
this.slines.clear();
this.slines.add(sbytes);
try (FileInputStream reader = new FileInputStream(file)) {
if (sbytes > -Long.MAX_VALUE) {
if (sbytes > 0) {
reader.skip(sbytes);
reader.skip(Long.MAX_VALUE);
} else {
reader.skip(sbytes + Long.MAX_VALUE);
}
}
int i;
byte[] b = new byte[1024];
ByteArrayOutputStream stream = new ByteArrayOutputStream();
while ((i = reader.read(b)) != -1) {
stream.write(b, 0, i);
}
submit(stream.toString(UTF_8.name()));
} catch (Exception e) {
e.printStackTrace();
}
}
public void log(Date date, String message) {
private void submit(final String s) {
thread.submit(new Runnable() {
@Override
public void run() {
try {
int begin = 0;
int end, i, bytes;
do {
i = s.indexOf('\n', begin);
end = (i == -1) ? s.length() : i + 1;
// Submit the text (without any newlines)
stream.write(s.substring(begin, (i == -1) ? s.length() : i).getBytes(UTF_8));
// Count the bytes (with 1 possible newline)
bytes = s.substring(begin, end).getBytes(UTF_8).length;
if (sbytes + bytes < sbytes) sbytes = Long.MAX_VALUE;
else sbytes += bytes;
// Submit a newline if necessary
if (i != -1) {
stream.closeAttributes();
stream.write("\u00A0".getBytes(UTF_8));
stream.flush();
stream.write("\n\u00A0".getBytes(UTF_8));
slines.add(sbytes);
while (slines.size() > MAX_SCROLLBACK + 1) {
slines.removeFirst();
}
}
// Continue to the next line if available
begin = end;
} while (begin < s.length());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
public void log(String message) {
message += '\n';
try {
messages.add(('\u00A0' + new SimpleDateFormat("hh:mm:ss").format(date) + ' ' + message + "\u00A0\n").getBytes("UTF-8"));
filewriter.write(message.getBytes(UTF_8));
filewriter.flush();
submit(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public void log(String message) {
log(Calendar.getInstance().getTime(), message);
public void log(Date date, String message) {
log(new SimpleDateFormat("hh:mm:ss").format(date) + ' ' + message);
}
public void log(Date date, Level level, String message) {
log(date, "[" + level.getLocalizedName() + "] " + message);
@ -636,64 +731,16 @@ public final class ConsoleWindow implements SubLogFilter {
return !open;
}
private void log() {
new Thread("SubServers.Console::Log_Spooler(" + logger.getName() + ")") {
@Override
public void run() {
while (running) {
while (running && messages.size() > 0) try {
byte[] msg = (byte[]) Util.getDespiteException(new ExceptionReturnRunnable<Object>() {
@Override
public Object run() throws Throwable {
return messages.get(0);
}
}, null);
if (msg != null) {
filewriter.write(msg);
stream.write(msg);
}
try { ConsoleWindow.this.messages.remove(0); } catch (Throwable e) {}
} catch (Throwable e) {
try { ConsoleWindow.this.messages.remove(0); } catch (Throwable ex) {}
e.printStackTrace();
}
try { Thread.sleep(32); } catch (Throwable e) {}
}
}
}.start();
}
public void clear() {
log.setText(RESET_VALUE);
hScroll();
}
public void open() {
if (!open) {
window.setVisible(true);
this.open = true;
}
window.toFront();
log.setText("\n\u00A0\n\u00A0");
}
public boolean isOpen() {
return open;
}
@Override
public void start() {}
private void loadContent() {
if (file != null) {
try (FileInputStream reader = new FileInputStream(file)) {
int b;
while ((b = reader.read()) != -1) {
stream.write(b);
}
} catch (Exception e) {
e.printStackTrace();
}
hScroll();
}
public SubLogger getLogger() {
return logger;
}
@Override
@ -715,7 +762,7 @@ public final class ConsoleWindow implements SubLogFilter {
public void destroy() {
close();
running = false;
thread.shutdown();
logger.unregisterFilter(this);
if (filewriter != null) try {
filewriter.close();
@ -724,6 +771,13 @@ public final class ConsoleWindow implements SubLogFilter {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(keys);
}
private void hScroll() {
hScroll.setMaximum(vScroll.getHorizontalScrollBar().getMaximum());
hScroll.setMinimum(vScroll.getHorizontalScrollBar().getMinimum());
hScroll.setVisibleAmount(vScroll.getHorizontalScrollBar().getVisibleAmount());
hScroll.setVisible(input.isVisible() && hScroll.getVisibleAmount() < hScroll.getMaximum());
}
private void find(boolean direction) {
if (!direction) findI -= findO + 1;
String find = findT.getText().toLowerCase();
@ -887,6 +941,7 @@ public final class ConsoleWindow implements SubLogFilter {
private class AnsiUIOutputStream extends HTMLogger {
public AnsiUIOutputStream(OutputStream raw, OutputStream wrapped) {
super(raw, wrapped);
nbsp = true;
}
public void ansi(boolean value) {
@ -908,7 +963,8 @@ public final class ConsoleWindow implements SubLogFilter {
if (ansi) spost.add(new Runnable() {
@Override
public void run() {
log.setText(RESET_VALUE);
ConsoleWindow.this.clear();
ConsoleWindow.this.hScroll();
}
});
}
@ -940,11 +996,11 @@ public final class ConsoleWindow implements SubLogFilter {
}
}
private class SmartScroller implements AdjustmentListener {
public final static int HORIZONTAL = 0;
public final static int VERTICAL = 1;
private final static int HORIZONTAL = 0;
private final static int VERTICAL = 1;
public final static int START = 0;
public final static int END = 1;
private final static int START = 0;
private final static int END = 1;
private int viewportPosition;

View File

@ -1,82 +1,74 @@
package net.ME1312.SubServers.Console.Library;
import net.ME1312.Galaxi.Library.Container.Container;
import net.ME1312.Galaxi.Library.Container.Value;
import org.fusesource.jansi.AnsiOutputStream;
import java.awt.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.Locale;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* HTML Log Stream Class
*/
public class HTMLogger extends AnsiOutputStream {
private static final String[] ANSI_COLOR_MAP = new String[]{"000000", "cd0000", "25bc24", "d7d700", "0000c3", "be00be", "00a5dc", "cccccc"};
private static final String[] ANSI_BRIGHT_COLOR_MAP = new String[]{"808080", "ff0000", "31e722", "ffff00", "0000ff", "ff00ff", "00c8ff", "ffffff"};
private static final byte[] BYTES_NBSP = "&nbsp;".getBytes();
private static final byte[] BYTES_QUOT = "&quot;".getBytes();
private static final byte[] BYTES_AMP = "&amp;".getBytes();
private static final byte[] BYTES_LT = "&lt;".getBytes();
private static final byte[] BYTES_GT = "&gt;".getBytes();
private LinkedList<String> closingAttributes = new LinkedList<String>();
private static final byte[] BYTES_NBSP = "\u00A0".getBytes(UTF_8);
private static final byte[] BYTES_AMP = "&amp;".getBytes(UTF_8);
private static final byte[] BYTES_LT = "&lt;".getBytes(UTF_8);
private LinkedList<String> currentAttributes = new LinkedList<String>();
private LinkedList<String> queue = new LinkedList<String>();
private OutputStream raw;
protected boolean ansi = true;
protected boolean nbsp = false;
private boolean underline = false;
private boolean strikethrough = false;
/**
* Parse data from an OutputStream
*
* @param raw OutputStream
* @return HTMLogger
*/
public static HTMLogger wrap(OutputStream raw) {
return wrap(raw, new HTMConstructor<HTMLogger>() {
@Override
public HTMLogger construct(OutputStream raw1, OutputStream wrapped) {
return new HTMLogger(raw1, wrapped);
public HTMLogger construct(OutputStream raw, OutputStream wrapped) {
return new HTMLogger(raw, wrapped);
}
});
}
/**
* Parse data from an OutputStream
*
* @param raw OutputStream
* @param constructor Implementing Constructor
* @param <T> Logger Type
* @return HTMLogger
*/
public static <T extends HTMLogger> T wrap(final OutputStream raw, HTMConstructor<T> constructor) {
final Value<T> html = new Container<T>(null);
final Container<T> html = new Container<T>(null);
html.value(constructor.construct(raw, new OutputStream() {
private boolean nbsp = false;
@Override
public void write(int data) throws IOException {
HTMLogger htm = html.value();
if (htm.queue.size() > 0) {
LinkedList<String> queue = htm.queue;
htm.queue = new LinkedList<>();
for (String attr : queue) {
htm.write('<' + attr + '>');
htm.currentAttributes.addFirst(attr);
}
}
if (data == 32) {
if (nbsp) raw.write(BYTES_NBSP);
else raw.write(data);
nbsp = !nbsp;
if (htm.nbsp) {
if (nbsp) raw.write(BYTES_NBSP);
else raw.write(data);
nbsp = !nbsp;
} else raw.write(data);
} else {
nbsp = false;
switch(data) {
case 34:
raw.write(BYTES_QUOT);
break;
case 38:
case '&':
raw.write(BYTES_AMP);
break;
case 60:
case '<':
raw.write(BYTES_LT);
break;
case 62:
raw.write(BYTES_GT);
break;
case 10:
html.value().closeAttributes();
case '\n':
htm.closeAttributes();
default:
raw.write(data);
}
@ -85,7 +77,7 @@ public class HTMLogger extends AnsiOutputStream {
}));
return html.value();
}
protected HTMLogger(final OutputStream raw, OutputStream wrapped) {
public HTMLogger(final OutputStream raw, OutputStream wrapped) {
super(wrapped);
this.raw = raw;
}
@ -94,46 +86,62 @@ public class HTMLogger extends AnsiOutputStream {
}
private void write(String s) throws IOException {
raw.write(s.getBytes());
raw.write(s.getBytes(UTF_8));
}
private void writeAttribute(String s) throws IOException {
write("<" + s + ">");
closingAttributes.add(0, s);
private void writeAttribute(String attr) throws IOException {
queue.add(attr);
}
protected void closeAttribute(String s) throws IOException {
public void closeAttribute(String s) throws IOException {
// Try to remove a tag that doesn't exist yet first
String[] queue = this.queue.toArray(new String[0]);
for (int i = queue.length; i > 0;) {
String attr = queue[--i];
if (attr.toLowerCase().startsWith(s.toLowerCase())) {
this.queue.removeLastOccurrence(attr);
return;
}
}
// Close a tag that we've already written
LinkedList<String> closedAttributes = new LinkedList<String>();
LinkedList<String> closingAttributes = new LinkedList<String>();
LinkedList<String> currentAttributes = new LinkedList<String>(this.currentAttributes);
LinkedList<String> unclosedAttributes = new LinkedList<String>();
closingAttributes.addAll(closingAttributes);
for (String attr : closingAttributes) {
for (String attr : currentAttributes) {
if (attr.toLowerCase().startsWith(s.toLowerCase())) {
for (String a : unclosedAttributes) {
closedAttributes.add(0, a);
write("</" + a.split(" ", 2)[0] + ">");
closedAttributes.add(a);
this.currentAttributes.removeFirst();
write("</" + a.split(" ", 2)[0] + '>');
}
closingAttributes.removeFirstOccurrence(attr);
unclosedAttributes.clear();
write("</" + attr.split(" ", 2)[0] + ">");
this.currentAttributes.removeFirst();
write("</" + attr.split(" ", 2)[0] + '>');
break;
} else {
unclosedAttributes.add(attr);
}
}
// Queue unrelated tags to be re-opened
for (String attr : closedAttributes) {
write("<" + attr + ">");
this.queue.addFirst(attr);
}
}
protected void closeAttributes() throws IOException {
for (String attr : closingAttributes) {
public void closeAttributes() throws IOException {
queue.clear();
for (String attr : currentAttributes) {
write("</" + attr.split(" ", 2)[0] + ">");
}
underline = false;
strikethrough = false;
closingAttributes.clear();
currentAttributes.clear();
}
@Override
@ -141,13 +149,13 @@ public class HTMLogger extends AnsiOutputStream {
super.processDeleteLine(amount);
}
private String parseTextDecoration() {
private void renderTextDecoration() throws IOException {
String dec = "";
if (underline) dec += " underline";
if (strikethrough) dec += " line-through";
if (dec.length() <= 0) dec += " none";
return dec.substring(1);
closeAttribute("span style=\"text-decoration:");
if (dec.length() != 0) writeAttribute("span style=\"text-decoration:" + dec.substring(1) + "\"");
}
@Override
@ -162,14 +170,12 @@ public class HTMLogger extends AnsiOutputStream {
writeAttribute("i");
break;
case 4:
closeAttribute("span class=\"ansi-decoration");
underline = true;
writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\"");
renderTextDecoration();
break;
case 9:
closeAttribute("span class=\"ansi-decoration");
strikethrough = true;
writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\"");
renderTextDecoration();
break;
case 22:
closeAttribute("b");
@ -178,14 +184,23 @@ public class HTMLogger extends AnsiOutputStream {
closeAttribute("i");
break;
case 24:
closeAttribute("span class=\"ansi-decoration");
underline = false;
writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\"");
renderTextDecoration();
break;
case 29:
closeAttribute("span class=\"ansi-decoration");
strikethrough = false;
writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\"");
renderTextDecoration();
break;
case 73:
closeAttribute("su");
writeAttribute("sup");
break;
case 74:
closeAttribute("su");
writeAttribute("sub");
break;
case 75:
closeAttribute("su");
break;
}
}
@ -193,24 +208,30 @@ public class HTMLogger extends AnsiOutputStream {
@Override
protected void processUnknownOperatingSystemCommand(int label, String arg) {
try {
if (ansi) switch (label) {
case 99900: // Galaxi Console Exclusives 99900-99999
closeAttribute("a");
writeAttribute("a href=\"" + arg + "\" target=\"_blank\"");
break;
case 99901:
closeAttribute("a");
break;
if (ansi && label == 8) {
closeAttribute("a");
String[] args = arg.split(";", 3);
if (args.length > 1 && args[1].length() > 0 && allowHyperlink(args[1])) {
writeAttribute("a href=\"" + args[1].replace("&", "&amp;").replace("<", "&lt;").replace("\"", "&quot;") + "\" target=\"_blank\"");
}
}
} catch (Exception e) {}
}
protected boolean allowHyperlink(String link) {
if (link.toLowerCase(Locale.ENGLISH).startsWith("mailto:execute@galaxi.engine")) {
return false;
} else {
return true;
}
}
@Override
protected void processAttributeRest() throws IOException {
closeAttributes();
}
private String parse8BitColor(int color) throws IOException {
private String parse256(int color) throws IOException {
if (color < 8) {
return ANSI_COLOR_MAP[color];
} else if (color < 16) {
@ -230,7 +251,7 @@ public class HTMLogger extends AnsiOutputStream {
@Override
protected void processDefaultTextColor() throws IOException {
closeAttribute("span class=\"ansi-foreground");
closeAttribute("span style=\"color:");
}
@Override
@ -242,7 +263,8 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetForegroundColor(int color, boolean bright) throws IOException {
if (ansi) {
processDefaultTextColor();
writeAttribute("span class=\"ansi-foreground\" style=\"color: #" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + ";\"");
writeAttribute("span style=\"color:#" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + "\"");
renderTextDecoration();
}
}
@ -250,7 +272,8 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetForegroundColorExt(int index) throws IOException {
if (ansi) {
processDefaultTextColor();
writeAttribute("span class=\"ansi-foreground\" style=\"color: #" + parse8BitColor(index) + ";\"");
writeAttribute("span style=\"color:#" + parse256(index) + "\"");
renderTextDecoration();
}
}
@ -258,13 +281,14 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetForegroundColorExt(int r, int g, int b) throws IOException {
if (ansi) {
processDefaultTextColor();
writeAttribute("span class=\"ansi-foreground\" style=\"color: #" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + ";\"");
writeAttribute("span style=\"color:#" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + "\"");
renderTextDecoration();
}
}
@Override
protected void processDefaultBackgroundColor() throws IOException {
closeAttribute("span class=\"ansi-background");
closeAttribute("span style=\"background-color:");
}
@Override
@ -276,7 +300,7 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
if (ansi) {
processDefaultBackgroundColor();
writeAttribute("span class=\"ansi-background\" style=\"background-color: #" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + ";\"");
writeAttribute("span style=\"background-color:#" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + "\"");
}
}
@ -284,7 +308,7 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetBackgroundColorExt(int index) throws IOException {
if (ansi) {
processDefaultBackgroundColor();
writeAttribute("span class=\"ansi-background\" style=\"background-color: #" + parse8BitColor(index) + ";\"");
writeAttribute("span style=\"background-color:#" + parse256(index) + "\"");
}
}
@ -292,10 +316,16 @@ public class HTMLogger extends AnsiOutputStream {
protected void processSetBackgroundColorExt(int r, int g, int b) throws IOException {
if (ansi) {
processDefaultBackgroundColor();
writeAttribute("span class=\"ansi-background\" style=\"background-color: #" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + ";\"");
writeAttribute("span style=\"background-color:#" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + "\"");
}
}
@Override
public void flush() throws IOException {
super.flush();
raw.flush();
}
@Override
public void close() throws IOException {
closeAttributes();