Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update TerminalConsoleAppender #276

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

/**
* A simplified version of {@link HighlightConverter} that uses
* {@link TerminalConsoleAppender} to detect if Ansi escape codes can be used
* {@link TerminalConsoleAppender} to detect if ANSI escape codes can be used
* to highlight errors and warnings in the console.
*
* <p>If configured, it will mark all logged errors with a red color and all
Expand All @@ -55,9 +55,9 @@
@PerformanceSensitive("allocation")
public class HighlightErrorConverter extends LogEventPatternConverter
{
private static final String ANSI_RESET = "\u001B[39;0m";
private static final String ANSI_ERROR = "\u001B[31;1m";
private static final String ANSI_WARN = "\u001B[33;1m";
private static final String ANSI_RESET = "\u001B[m";
private static final String ANSI_ERROR = "\u001B[31;1m"; // Bold Red
private static final String ANSI_WARN = "\u001B[33;1m"; // Bold Yellow

private final List<PatternFormatter> formatters;

Expand Down Expand Up @@ -142,8 +142,7 @@ public boolean handlesThrowable()
* @param options The pattern options
* @return The new instance
*/
@Nullable
public static HighlightErrorConverter newInstance(Configuration config, String[] options)
public static @Nullable HighlightErrorConverter newInstance(Configuration config, String[] options)
{
if (options.length != 1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@
*
* @see <a href="http://minecraft.gamepedia.com/Formatting_codes">
* Formatting Codes</a>
* @deprecated Minecraft-specific. Also, legacy formatting codes are deprecated
* and do not natively allow specifying RGB colors. Consider implementing
* native support for the (JSON) chat components of your platform instead.
* For more information, see
* <a href="https://github.com/Minecrell/TerminalConsoleAppender/issues/18">issue #18</a>.
*/
@Plugin(name = "minecraftFormatting", category = PatternConverter.CATEGORY)
@ConverterKeys({ "minecraftFormatting" })
@PerformanceSensitive("allocation")
@Deprecated
public class MinecraftFormattingConverter extends LogEventPatternConverter
{

Expand All @@ -77,34 +83,34 @@ public class MinecraftFormattingConverter extends LogEventPatternConverter

private static final boolean KEEP_FORMATTING = PropertiesUtil.getProperties().getBooleanProperty(KEEP_FORMATTING_PROPERTY);

private static final String ANSI_RESET = "\u001B[m";
static final String ANSI_RESET = "\u001B[m";

private static final char COLOR_CHAR = '\u00A7'; // §
private static final char COLOR_CHAR = '§';
private static final String LOOKUP = "0123456789abcdefklmnor";

private static final String[] ansiCodes = new String[] {
"\u001B[0;30m", // Black §0
"\u001B[0;34m", // Dark Blue §1
"\u001B[0;32m", // Dark Green §2
"\u001B[0;36m", // Dark Aqua §3
"\u001B[0;31m", // Dark Red §4
"\u001B[0;35m", // Dark Purple §5
"\u001B[0;33m", // Gold §6
"\u001B[0;37m", // Gray §7
"\u001B[0;30;1m", // Dark Gray §8
"\u001B[0;34;1m", // Blue §9
"\u001B[0;32;1m", // Green §a
"\u001B[0;36;1m", // Aqua §b
"\u001B[0;31;1m", // Red §c
"\u001B[0;35;1m", // Light Purple §d
"\u001B[0;33;1m", // Yellow §e
"\u001B[0;37;1m", // White §f
"\u001B[5m", // Obfuscated §k
"\u001B[21m", // Bold §l
"\u001B[9m", // Strikethrough §m
"\u001B[4m", // Underline §n
"\u001B[3m", // Italic §o
ANSI_RESET, // Reset §r
"\u001B[0;30m", // Black §0
"\u001B[0;34m", // Dark Blue §1
"\u001B[0;32m", // Dark Green §2
"\u001B[0;36m", // Dark Aqua §3
"\u001B[0;31m", // Dark Red §4
"\u001B[0;35m", // Dark Purple §5
"\u001B[0;33m", // Gold §6
"\u001B[0;37m", // Gray §7
"\u001B[0;30;1m", // Dark Gray §8
"\u001B[0;34;1m", // Blue §9
"\u001B[0;32;1m", // Green §a
"\u001B[0;36;1m", // Aqua §b
"\u001B[0;31;1m", // Red §c
"\u001B[0;35;1m", // Light Purple §d
"\u001B[0;33;1m", // Yellow §e
"\u001B[0;37;1m", // White §f
"\u001B[5m", // Obfuscated §k
"\u001B[21m", // Bold §l
"\u001B[9m", // Strikethrough §m
"\u001B[4m", // Underline §n
"\u001B[3m", // Italic §o
ANSI_RESET, // Reset §r
};

private final boolean ansi;
Expand Down Expand Up @@ -143,7 +149,7 @@ public void format(LogEvent event, StringBuilder toAppendTo)
format(content, toAppendTo, start, ansi && TerminalConsoleAppender.isAnsiSupported());
}

private static void format(String s, StringBuilder result, int start, boolean ansi)
static void format(String s, StringBuilder result, int start, boolean ansi)
{
int next = s.indexOf(COLOR_CHAR);
int last = s.length() - 1;
Expand Down Expand Up @@ -195,8 +201,7 @@ private static void format(String s, StringBuilder result, int start, boolean an
*
* @see MinecraftFormattingConverter
*/
@Nullable
public static MinecraftFormattingConverter newInstance(Configuration config, String[] options)
public static @Nullable MinecraftFormattingConverter newInstance(Configuration config, String[] options)
{
if (options.length < 1 || options.length > 2)
{
Expand All @@ -214,4 +219,5 @@ public static MinecraftFormattingConverter newInstance(Configuration config, Str
boolean strip = options.length > 1 && "strip".equals(options[1]);
return new MinecraftFormattingConverter(formatters, strip);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package net.minecraftforge.server.terminalconsole;

import org.apache.logging.log4j.LogManager;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jline.reader.Completer;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.UserInterruptException;
import org.jline.terminal.Terminal;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
* A simple, optional base implementation of a basic console input command
* reader using {@link TerminalConsoleAppender}. Once started, it displays
* a command prompt ("{@code > }") and reads input commands from the console.
*
* <p><strong>Usage:</strong> Extend this class and implement the abstract
* methods for your application. Consider overriding
* {@link #buildReader(LineReaderBuilder)} to add further features to the
* console (e.g. call {@link LineReaderBuilder#completer(Completer)} with
* a custom completer to provide command completion).</p>
*/
public abstract class SimpleTerminalConsole {

/**
* Determines if the application is still running and accepting input.
*
* @return {@code true} to continue reading input
*/
protected abstract boolean isRunning();

/**
* Run a command entered in the console.
*
* @param command The command line to run
*/
protected abstract void runCommand(String command);

/**
* Shutdown the application and perform a clean exit.
*
* <p>This is called if the application receives SIGINT while reading input,
* e.g. when pressing CTRL+C on most terminal implementations.</p>
*/
protected abstract void shutdown();

/**
* Process an input line entered through the console.
*
* <p>The default implementation trims leading and trailing whitespace
* from the input and skips execution if the command is empty.</p>
*
* @param input The input line
*/
protected void processInput(String input) {
String command = input.trim();
if (!command.isEmpty()) {
runCommand(command);
}
}

/**
* Configures the {@link LineReaderBuilder} and {@link LineReader} with
* additional options.
*
* <p>Override this method to make further changes, (e.g. call
* {@link LineReaderBuilder#appName(String)} or
* {@link LineReaderBuilder#completer(Completer)}).</p>
*
* <p>The default implementation sets some opinionated default options,
* which are considered to be appropriate for most applications:</p>
*
* <ul>
* <li>{@link LineReader.Option#DISABLE_EVENT_EXPANSION}: JLine implements
* <a href="http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html">
* Bash's Event Designators</a> by default. These usually do not
* behave as expected in a simple command environment, so it's
* recommended to disable it.</li>
* <li>{@link LineReader.Option#INSERT_TAB}: By default, JLine inserts
* a tab character when attempting to tab-complete on empty input.
* It is more intuitive to show a list of commands instead.</li>
* </ul>
*
* @param builder The builder to configure
* @return The built line reader
*/
protected LineReader buildReader(LineReaderBuilder builder) {
LineReader reader = builder.build();
reader.setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION);
reader.unsetOpt(LineReader.Option.INSERT_TAB);
return reader;
}

/**
* Start reading commands from the console.
*
* <p>Note that this method won't return until one of the following
* conditions are met:</p>
*
* <ul>
* <li>{@link #isRunning()} returns {@code false}, indicating that the
* application is shutting down.</li>
* <li>{@link #shutdown()} is triggered by the user (e.g. due to
* pressing CTRL+C)</li>
* <li>The input stream is closed.</li>
* </ul>
*/
public void start() {
try {
final @Nullable Terminal terminal = TerminalConsoleAppender.getTerminal();
if (terminal != null) {
readCommands(terminal);
} else {
readCommands(System.in);
}
} catch (IOException e) {
LogManager.getLogger("TerminalConsole").error("Failed to read console input", e);
}
}

private void readCommands(Terminal terminal) {
LineReader reader = buildReader(LineReaderBuilder.builder().terminal(terminal));
TerminalConsoleAppender.setReader(reader);

try {
String line;
while (isRunning()) {
try {
line = reader.readLine("> ");
} catch (EndOfFileException ignored) {
// Continue reading after EOT
continue;
}

if (line == null) {
break;
}

processInput(line);
}
} catch (UserInterruptException e) {
shutdown();
} finally {
TerminalConsoleAppender.setReader(null);
}
}

private void readCommands(InputStream in) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
String line;
while (isRunning() && (line = reader.readLine()) != null) {
processInput(line);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.minecraftforge.server.terminalconsole;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.AbstractLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A {@link StrLookup} that returns properties specific to
* {@link TerminalConsoleAppender}. The following properties are supported:
*
* <ul>
* <li>{@code ${tca:disableAnsi}}: Can be used together with
* {@code PatternLayout} to disable ANSI colors for patterns like
* {@code %highlight} or {@code %style} if ANSI colors are unsupported
* or are disabled for {@link TerminalConsoleAppender}.
*
* <p><b>Example usage:</b>
* {@code <PatternLayout ... disableAnsi="${tca:disableAnsi}">}</p></li>
* </ul>
*/
@Plugin(name = "tca", category = StrLookup.CATEGORY)
public final class TCALookup extends AbstractLookup {

/**
* Lookup key that returns if ANSI colors are unsupported/disabled.
*/
public final static String KEY_DISABLE_ANSI = "disableAnsi";

@Override
@Nullable
public String lookup(LogEvent event, String key) {
if (KEY_DISABLE_ANSI.equals(key)) {
return String.valueOf(!TerminalConsoleAppender.isAnsiSupported());
}
return null;
}

}
Loading
Loading