diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiEscapeTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiEscapeTest.java new file mode 100644 index 00000000000..6f1d355dd35 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiEscapeTest.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.core.pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * Regression tests for ANSI SGR attribute codes (GitHub issue #4105). + *

+ * Expected values are hard-coded SGR sequences so a wrong mapping cannot + * compare equal to itself. + *

+ */ +class AnsiEscapeTest { + + @ParameterizedTest + @CsvSource({ + // Log4j style names + "normal, 0", + "bold, 1", + "dim, 2", + "italic, 3", + "underline, 4", + "blink, 5", + "reverse, 7", + "hidden, 8", + // Jansi AnsiRenderer.Code names / aliases (post-#3070 parity) + "reset, 0", + "intensity_bold, 1", + "faint, 2", + "intensity_faint, 2", + "blink_slow, 5", + "blink_fast, 6", + "blink_off, 25", + "negative_on, 7", + "negative_off, 27", + "conceal_on, 8", + "conceal_off, 28", + "underline_double, 21", + "underline_off, 24", + "bg_default, 49", + }) + void styleMapsToSgr(final String name, final String sgrCode) { + assertEquals("\u001B[" + sgrCode + "m", AnsiEscape.createSequence(name)); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/JAnsiTextRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/JAnsiTextRendererTest.java index 0595f68533d..129829b1e0a 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/JAnsiTextRendererTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/JAnsiTextRendererTest.java @@ -39,6 +39,14 @@ public static Stream testRendering() { "", "@|white key|@ = @|cyan,bold some value|@", "\u001b[37mkey\u001b[m = \u001b[36;1msome value\u001b[m"), + Arguments.of( + "", + "@|italic italic text|@ and @|underline underlined text|@", + "\u001b[3mitalic text\u001b[m and \u001b[4munderlined text\u001b[m"), + Arguments.of( + "", + "@|faint faint text|@ and @|blink_slow blinking text|@", + "\u001b[2mfaint text\u001b[m and \u001b[5mblinking text\u001b[m"), // Return broken escapes as is Arguments.of("", "Hello @|crazy|@ world!", "Hello @|crazy|@ world!"), Arguments.of("", "Hello @|world!", "Hello @|world!")); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java index 34213373dfb..7b647f854df 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java @@ -58,6 +58,11 @@ public enum AnsiEscape { */ NORMAL("0"), + /** + * Reset general attribute (Jansi {@code AnsiRenderer.Code} name). + */ + RESET("0"), + /** * Bright general attribute. * @@ -72,31 +77,96 @@ public enum AnsiEscape { */ BOLD("1"), + /** + * Bold intensity attribute (Jansi {@code AnsiRenderer.Code} name). + */ + INTENSITY_BOLD("1"), + /** * Dim general attribute. */ DIM("2"), + /** + * Faint / dim general attribute (Jansi {@code AnsiRenderer.Code} name). + */ + FAINT("2"), + + /** + * Faint intensity attribute (Jansi {@code AnsiRenderer.Code} name). + */ + INTENSITY_FAINT("2"), + + /** + * Italic general attribute. + */ + ITALIC("3"), + /** * Underline general attribute. */ - UNDERLINE("3"), + UNDERLINE("4"), /** * Blink general attribute. */ BLINK("5"), + /** + * Slow blink general attribute (Jansi {@code AnsiRenderer.Code} name). + */ + BLINK_SLOW("5"), + + /** + * Fast blink general attribute. + */ + BLINK_FAST("6"), + /** * Reverse general attribute. */ REVERSE("7"), /** - * Normal general attribute. + * Reverse / negative general attribute (Jansi {@code AnsiRenderer.Code} name). + */ + NEGATIVE_ON("7"), + + /** + * Conceal / hidden general attribute. */ HIDDEN("8"), + /** + * Conceal general attribute (Jansi {@code AnsiRenderer.Code} name). + */ + CONCEAL_ON("8"), + + /** + * Double underline general attribute. + */ + UNDERLINE_DOUBLE("21"), + + /** + * Turns underline off. + */ + UNDERLINE_OFF("24"), + + /** + * Turns blink off. + */ + BLINK_OFF("25"), + + /** + * Turns reverse / negative video off. + */ + NEGATIVE_OFF("27"), + + /** + * Turns conceal off. + */ + CONCEAL_OFF("28"), + /** * Black foreground color. */ @@ -227,6 +297,11 @@ public enum AnsiEscape { */ BG_WHITE("47"), + /** + * Default background color. + */ + BG_DEFAULT("49"), + /** * Bright black foreground color. */ diff --git a/src/changelog/.2.x.x/4105_fix_AnsiEscape_italic_underline.xml b/src/changelog/.2.x.x/4105_fix_AnsiEscape_italic_underline.xml new file mode 100644 index 00000000000..1452cb793e4 --- /dev/null +++ b/src/changelog/.2.x.x/4105_fix_AnsiEscape_italic_underline.xml @@ -0,0 +1,12 @@ + + + + + Fix `AnsiEscape` italic/underline SGR codes and restore missing Jansi `AnsiRenderer.Code` style names (for example `faint`, `blink_slow`) + + diff --git a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc index 4e3943066a7..84781f1d552 100644 --- a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc @@ -1465,8 +1465,8 @@ In EBNF form the syntax of a style expression is: | ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" - ::= "normal" | "bold" | "dim" | "underline" - | "blink" | "reverse" | "hidden" + ::= "normal" | "reset" | "bold" | "dim" | "faint" | "italic" | "underline" + | "underline_double" | "blink" | "blink_slow" | "blink_fast" | "reverse" | "hidden" | "black" | "bg_black" | "bright_black" | "bg_bright_black" | "red" | "bg_red" | "bright_red" | "bg_bright_red" | "green" | "bg_green" | "bright_green" | "bg_bright_green" @@ -1481,11 +1481,14 @@ For example, you can use `underline blue bg_bright_yellow` to specify a blue und The style specifiers have the following effects (see https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters[Select Graphic Rendition] for details): -`normal`:: Reverts all parameters to their default value +`normal` / `reset`:: Reverts all parameters to their default value `bold`:: Increases the font weight or the color intensity -`dim`:: Decreases the fond weight or the color intensity +`dim` / `faint`:: Decreases the font weight or the color intensity +`italic`:: Renders the text in italic on terminals that support it `underline`:: Underlines the text on some terminals -`blink`:: Causes the text to blink +`underline_double`:: Double-underlines the text on terminals that support it +`blink` / `blink_slow`:: Causes the text to blink +`blink_fast`:: Causes the text to blink rapidly on terminals that support it `reverse`:: Swaps foreground and background colors `hidden`:: Hides the text