0

Only use ColorMapper if jAnsi is present, ignore it if not

This change allows slf4bukkit to run on Bukkit implementations without jansi by making ColorMapper an interface. Instances are created by using a ColorMappingFactory: If the Bukkit implementation bundles jAnsi, an AnsiColorMapper is returned that maps ChatColors to their ansi equivalents; if the Bukkit implementation does not bundle jAnsi, a NotSupportedColorMapper is returned that returns strings as is.
This commit is contained in:
TheE
2017-07-31 16:43:19 +02:00
parent 43c308706c
commit c88eab84a8
5 changed files with 122 additions and 47 deletions

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2016 Ronald Jack Jenkins Jr.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package info.ronjenkins.slf4bukkit;
import com.google.common.collect.ImmutableMap;
import org.bukkit.ChatColor;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Attribute;
import java.util.Map;
/**
* Maps {@link ChatColor} values to their JAnsi equivalents.
*
* <p>This class might not always be instantiable as jansi might not be present at runtime.</p>
*
* @author Ronald Jack Jenkins Jr.
*/
final class AnsiColorMapper implements ColorMapper {
AnsiColorMapper() throws Throwable {
// Calling this constructor could result in a Throwable because JAnsi, which is required to execute code
// in this class, might not be present at runtime, thus expected classes are not found.
}
// @formatter:off
private final Map<ChatColor, String> MAP = ImmutableMap.<ChatColor, String>builder()
.put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString())
.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString())
.put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString())
.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString())
.put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString())
.put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString())
.put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString())
.put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString())
.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString())
.put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString())
.put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString())
.put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString())
.put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString())
.put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString())
.put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString())
.put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString())
.put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString())
.put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString())
.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString())
.put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString())
.put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString())
.put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString())
.build();
// @formatter:on
@Override
public String map(final String input) {
if (input == null) {
return "";
}
String output = input;
for (final Map.Entry<ChatColor, String> mapping : MAP.entrySet()) {
output = output.replace(mapping.getKey().toString(), mapping.getValue());
}
return output;
}
}

View File

@@ -16,63 +16,21 @@
*/
package info.ronjenkins.slf4bukkit;
import java.util.Map;
import org.bukkit.ChatColor;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Attribute;
import com.google.common.collect.ImmutableMap;
/**
* Utility class that maps {@link ChatColor} values to their JAnsi equivalents,
* Utility class that maps {@link ChatColor} values to their equivalents,
* so that messages logged to the console are formatted correctly.
*
* @author Ronald Jack Jenkins Jr.
*/
public final class ColorMapper {
// @formatter:off
private static final Map<ChatColor, String> MAP = ImmutableMap.<ChatColor, String>builder()
.put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString())
.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString())
.put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString())
.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString())
.put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString())
.put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString())
.put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString())
.put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString())
.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString())
.put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString())
.put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString())
.put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString())
.put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString())
.put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString())
.put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString())
.put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString())
.put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString())
.put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString())
.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString())
.put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString())
.put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString())
.put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString())
.build();
// @formatter:on
public interface ColorMapper {
/**
* Translates {@link ChatColor} directives to their JAnsi equivalents.
* Translates {@link ChatColor} directives to their equivalents.
*
* @param input
* null is coerced to the empty string.
* @return never null.
*/
public static String map(final String input) {
if (input == null) { return ""; }
String output = input;
for (final Map.Entry<ChatColor, String> mapping : ColorMapper.MAP.entrySet()) {
output = output.replace(mapping.getKey().toString(), mapping.getValue());
}
return output;
}
String map(String input);
}

View File

@@ -0,0 +1,23 @@
package info.ronjenkins.slf4bukkit;
/**
* Creates {@code ColorMapper} instances.
*
* @see ColorMapper
*/
public final class ColorMapperFactory {
/**
* Creates an new {@code ColorMapper} instance.
*
* @return a new instance
*/
public static ColorMapper create() {
try {
return new AnsiColorMapper();
} catch (Throwable throwable) {
return new NotSupportedColorMapper();
}
}
}

View File

@@ -0,0 +1,12 @@
package info.ronjenkins.slf4bukkit;
/**
* Does not do any mapping but simply returns the given string or, if {@code null} is given, an empty string.
*/
final class NotSupportedColorMapper implements ColorMapper {
@Override
public String map(final String input) {
return input == null ? "" : input;
}
}

View File

@@ -45,6 +45,7 @@
package org.slf4j.impl;
import info.ronjenkins.slf4bukkit.ColorMapper;
import info.ronjenkins.slf4bukkit.ColorMapperFactory;
import info.ronjenkins.slf4bukkit.ColorMarker;
import java.io.IOException;
@@ -218,6 +219,7 @@ public final class BukkitLoggerAdapter implements Logger {
// The logger name.
private final String name;
// The short name of this simple log instance
private final ColorMapper mapper = ColorMapperFactory.create();
private transient String shortLogName = null;
// NOTE: BukkitPluginLoggerAdapter constructor should have only package access
@@ -1043,6 +1045,6 @@ public final class BukkitLoggerAdapter implements Logger {
// Log the message.
logger.log(BukkitLoggerAdapter.slf4jLevelIntToBukkitJULLevel(level),
ColorMapper.map(buf.toString()));
mapper.map(buf.toString()));
}
}