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

[LOGMGR-323] Add API for console feature detection #382

Merged
merged 1 commit into from
May 9, 2023
Merged
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 @@ -21,6 +21,7 @@

import org.jboss.logmanager.ExtLogRecord;
import org.jboss.logmanager.Level;
import org.jboss.logmanager.handlers.ConsoleHandler;

import java.util.logging.Formatter;
import java.util.logging.LogRecord;
Expand Down Expand Up @@ -53,17 +54,6 @@ public ColorPatternFormatter(int darken, final String pattern) {
setPattern(pattern);
}

static final boolean trueColor = determineTrueColor();

static boolean determineTrueColor() {
final String colorterm = System.getenv("COLORTERM");
return (colorterm != null && (colorterm.contains("truecolor") || colorterm.contains("24bit")));
}

static boolean isTrueColor() {
return trueColor;
}

public void setSteps(final FormatStep[] steps) {
FormatStep[] colorSteps = new FormatStep[steps.length];
for (int i = 0; i < steps.length; i++) {
Expand Down Expand Up @@ -146,6 +136,8 @@ public String formatMessage(final LogRecord logRecord) {
static final class ColorStep implements FormatStep {
private final int r, g, b;
private final FormatStep delegate;
// capture current console state
private final boolean trueColor = ConsoleHandler.isTrueColor();

ColorStep(final FormatStep delegate, final int r, final int g, final int b, final int darken) {
this.r = r >>> darken;
Expand All @@ -155,7 +147,7 @@ static final class ColorStep implements FormatStep {
}

public void render(final Formatter formatter, final StringBuilder builder, final ExtLogRecord record) {
ColorUtil.startFgColor(builder, isTrueColor(), r, g, b);
ColorUtil.startFgColor(builder, trueColor, r, g, b);
delegate.render(formatter, builder, record);
ColorUtil.endFgColor(builder);
}
Expand Down Expand Up @@ -183,6 +175,8 @@ static final class LevelColorStep implements FormatStep {
private static final int SATURATION = 66;
private final FormatStep delegate;
private final int darken;
// capture current console state
private final boolean trueColor = ConsoleHandler.isTrueColor();

LevelColorStep(final FormatStep delegate, final int darken) {
this.delegate = delegate;
Expand All @@ -195,7 +189,7 @@ public void render(final Formatter formatter, final StringBuilder builder, final
int r = ((level < 300 ? 0 : (level - 300) * (255 - SATURATION) / 300) + SATURATION) >>> darken;
int g = ((300 - abs(level - 300)) * (255 - SATURATION) / 300 + SATURATION) >>> darken;
int b = ((level > 300 ? 0 : level * (255 - SATURATION) / 300) + SATURATION) >>> darken;
ColorUtil.startFgColor(builder, isTrueColor(), r, g, b);
ColorUtil.startFgColor(builder, trueColor, r, g, b);
delegate.render(formatter, builder, record);
ColorUtil.endFgColor(builder);
}
Expand All @@ -212,10 +206,4 @@ public boolean isCallerInformationRequired() {
return false;
}
}

static final class TrueColorHolder {
private TrueColorHolder() {}

static final boolean trueColor = ColorPatternFormatter.determineTrueColor();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@
import java.util.Locale;
import java.util.UUID;

import org.jboss.logmanager.handlers.ConsoleHandler;

class ColorPrintf extends Printf {
private final int darken;
private final boolean trueColor = ConsoleHandler.isTrueColor();

ColorPrintf(final int darken) {
super(Locale.getDefault());
Expand Down Expand Up @@ -72,11 +75,11 @@ protected void formatFormattableString(final StringBuilder target, final Formatt

protected void formatPlainString(final StringBuilder target, final Object item, final GeneralFlags genFlags, final int width, final int precision) {
if (item instanceof Class || item instanceof Executable || item instanceof Field) {
ColorUtil.startFgColor(target, ColorPatternFormatter.trueColor, 0xff >>> darken, 0xff >>> darken, 0xdd >>> darken);
ColorUtil.startFgColor(target, trueColor, 0xff >>> darken, 0xff >>> darken, 0xdd >>> darken);
} else if (item instanceof UUID) {
ColorUtil.startFgColor(target, ColorPatternFormatter.trueColor, 0xdd >>> darken, 0xff >>> darken, 0xdd >>> darken);
ColorUtil.startFgColor(target, trueColor, 0xdd >>> darken, 0xff >>> darken, 0xdd >>> darken);
} else {
ColorUtil.startFgColor(target, ColorPatternFormatter.trueColor, 0xdd >>> darken, 0xdd >>> darken, 0xdd >>> darken);
ColorUtil.startFgColor(target, trueColor, 0xdd >>> darken, 0xdd >>> darken, 0xdd >>> darken);
}
super.formatPlainString(target, item, genFlags, width, precision);
ColorUtil.endFgColor(target);
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/org/jboss/logmanager/handlers/ConsoleHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,50 @@ private static Writer wrap(final Writer writer) {
public void setOutputStream(final OutputStream outputStream) {
super.setOutputStream(wrap(outputStream));
}

/**
* Determine whether the console exists.
* If the console does not exist, then the standard output stream will be used when {@link Target#CONSOLE} is
* selected as {@linkplain #setTarget(Target) the output target}.
*
* @return {@code true} if there is a console, {@code false} otherwise
*/
public static boolean hasConsole() {
return console != null;
}

/**
* Determine whether the console supports truecolor output.
* This call may be expensive, so the result should be captured for the lifetime of any formatter making use of
* this information.
*
* @return {@code true} if the console exists and supports truecolor output; {@code false} otherwise
*/
public static boolean isTrueColor() {
if (! hasConsole()) {
return false;
}
final String colorterm = System.getenv("COLORTERM");
return colorterm != null && (colorterm.contains("truecolor") || colorterm.contains("24bit"));
}

/**
* Determine whether the console can be passively detected to support graphical output.
* This call may be expensive, so the result should be captured for the lifetime of any formatter making use of
* this information.
*
* @return {@code true} if the console exists and supports graphical output; {@code false} otherwise or if
* graphical support cannot be passively detected
*/
public static boolean isGraphicsSupportPassivelyDetected() {
if (! hasConsole()) {
return false;
}
final String term = System.getenv("TERM");
final String termProgram = System.getenv("TERM_PROGRAM");
return term != null && (term.equalsIgnoreCase("kitty")
|| term.equalsIgnoreCase("wezterm")
|| term.equalsIgnoreCase("konsole")
) || termProgram != null && termProgram.equalsIgnoreCase("wezterm");
}
}