Repository: microsoft/vscode (TypeScript)
Date: 2021-04-09 03:14:51+00:00
Task type: Bug Fix

Issue:
Wrong style on debug console
Wrong style on debug console

- VSCode Version: 1.44.0-insider
  commit: 64b65cf8e401cb98d4ddfc8324cb6635ff6fc2ed
  data: 2020-03-20T08:31:26.505Z
- OS Version: Windows 10 2019 LTSC

Steps to Reproduce:

```js
// run code
console.log('\u001b[41m\u001b[97m [\u001b[4m\u001b[5mERROR\u001b[25m\u001b[24m] \u001b[0m\u001b[40m\u001b[97m \u001b[91m [method] Error，from: "X:\\xxx\\data.ts"\u001b[0m')
```

vscode:

![2020-03-23_09 38 21](https://user-images.githubusercontent.com/26459487/77272067-40e3b280-6ceb-11ea-90b3-e4233ec41e24.png)


cmd:

![2020-03-23_09 43 48](https://user-images.githubusercontent.com/26459487/77272081-4c36de00-6ceb-11ea-9523-908a029f436f.png)




Issue discussion:
Looks like an issue in core--I see the debug adapter is sending the identical string as gets logged

```

Logged:          \u001b[41m\u001b[97m [\u001b[4m\u001b[5mERROR\u001b[25m\u001b[24m] \u001b[0m\u001b[40m\u001b[97m \u001b[91m [method] Error，from: "X:\\xxx\\data.ts"\u001b[0m
Sent in output: "\u001b[41m\u001b[97m [\u001b[4m\u001b[5mERROR\u001b[25m\u001b[24m] \u001b[0m\u001b[40m\u001b[97m \u001b[91m [method] Error，from: \"X:\\xxx\\data.ts\"\u001b[0m\n"
```
Looks like ansi handling is off 
Code pointer https://github.com/microsoft/vscode/blob/2d85caa55586161faad7ce7c54e7335d3f14ac97/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts#L18

Solution patch:
diff --git a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts
--- a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts
+++ b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts
@@ -21,6 +21,8 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 	let styleNames: string[] = [];
 	let customFgColor: RGBA | undefined;
 	let customBgColor: RGBA | undefined;
+	let customUnderlineColor: RGBA | undefined;
+	let colorsInverted: boolean = false;
 	let currentPos: number = 0;
 	let buffer: string = '';
 
@@ -54,7 +56,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 			if (sequenceFound) {
 
 				// Flush buffer with previous styles.
-				appendStylizedStringToContainer(root, buffer, styleNames, linkDetector, workspaceFolder, customFgColor, customBgColor);
+				appendStylizedStringToContainer(root, buffer, styleNames, linkDetector, workspaceFolder, customFgColor, customBgColor, customUnderlineColor);
 
 				buffer = '';
 
@@ -62,17 +64,17 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 				 * Certain ranges that are matched here do not contain real graphics rendition sequences. For
 				 * the sake of having a simpler expression, they have been included anyway.
 				 */
-				if (ansiSequence.match(/^(?:[34][0-8]|9[0-7]|10[0-7]|[013]|4|[34]9)(?:;[349][0-7]|10[0-7]|[013]|[245]|[34]9)?(?:;[012]?[0-9]?[0-9])*;?m$/)) {
+				if (ansiSequence.match(/^(?:[34][0-8]|9[0-7]|10[0-7]|[0-9]|2[1-5,7-9]|[34]9|5[8,9]|1[0-9])(?:;[349][0-7]|10[0-7]|[013]|[245]|[34]9)?(?:;[012]?[0-9]?[0-9])*;?m$/)) {
 
 					const styleCodes: number[] = ansiSequence.slice(0, -1) // Remove final 'm' character.
 						.split(';')										   // Separate style codes.
 						.filter(elem => elem !== '')			           // Filter empty elems as '34;m' -> ['34', ''].
 						.map(elem => parseInt(elem, 10));		           // Convert to numbers.
 
-					if (styleCodes[0] === 38 || styleCodes[0] === 48) {
+					if (styleCodes[0] === 38 || styleCodes[0] === 48 || styleCodes[0] === 58) {
 						// Advanced color code - can't be combined with formatting codes like simple colors can
 						// Ignores invalid colors and additional info beyond what is necessary
-						const colorType = (styleCodes[0] === 38) ? 'foreground' : 'background';
+						const colorType = (styleCodes[0] === 38) ? 'foreground' : ((styleCodes[0] === 48) ? 'background' : 'underline');
 
 						if (styleCodes[1] === 5) {
 							set8BitColor(styleCodes, colorType);
@@ -100,7 +102,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 
 	// Flush remaining text buffer if not empty.
 	if (buffer) {
-		appendStylizedStringToContainer(root, buffer, styleNames, linkDetector, workspaceFolder, customFgColor, customBgColor);
+		appendStylizedStringToContainer(root, buffer, styleNames, linkDetector, workspaceFolder, customFgColor, customBgColor, customUnderlineColor);
 	}
 
 	return root;
@@ -109,15 +111,18 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 	 * Change the foreground or background color by clearing the current color
 	 * and adding the new one.
 	 * @param colorType If `'foreground'`, will change the foreground color, if
-	 * 	`'background'`, will change the background color.
+	 * 	`'background'`, will change the background color, and if `'underline'`
+	 * will set the underline color.
 	 * @param color Color to change to. If `undefined` or not provided,
 	 * will clear current color without adding a new one.
 	 */
-	function changeColor(colorType: 'foreground' | 'background', color?: RGBA | undefined): void {
+	function changeColor(colorType: 'foreground' | 'background' | 'underline', color?: RGBA | undefined): void {
 		if (colorType === 'foreground') {
 			customFgColor = color;
 		} else if (colorType === 'background') {
 			customBgColor = color;
+		} else if (colorType === 'underline') {
+			customUnderlineColor = color;
 		}
 		styleNames = styleNames.filter(style => style !== `code-${colorType}-colored`);
 		if (color !== undefined) {
@@ -126,44 +131,165 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 	}
 
 	/**
-	 * Calculate and set basic ANSI formatting. Supports bold, italic, underline,
-	 * normal foreground and background colors, and bright foreground and
+	 * Swap foreground and background colors.  Used for color inversion.  Caller should check
+	 * [] flag to make sure it is appropriate to turn ON or OFF (if it is already inverted don't call
+	 */
+	function reverseForegroundAndBackgroundColors(): void {
+		let oldFgColor: RGBA | undefined;
+		oldFgColor = customFgColor;
+		changeColor('foreground', customBgColor);
+		changeColor('background', oldFgColor);
+	}
+
+	/**
+	 * Calculate and set basic ANSI formatting. Supports ON/OFF of bold, italic, underline,
+	 * double underline,  crossed-out/strikethrough, overline, dim, blink, rapid blink,
+	 * reverse/invert video, hidden, superscript, subscript and alternate font codes,
+	 * clearing/resetting of foreground, background and underline colors,
+	 * setting normal foreground and background colors, and bright foreground and
 	 * background colors. Not to be used for codes containing advanced colors.
 	 * Will ignore invalid codes.
 	 * @param styleCodes Array of ANSI basic styling numbers, which will be
 	 * applied in order. New colors and backgrounds clear old ones; new formatting
 	 * does not.
-	 * @see {@link https://en.wikipedia.org/wiki/ANSI_escape_code }
+	 * @see {@link https://en.wikipedia.org/wiki/ANSI_escape_code#SGR }
 	 */
 	function setBasicFormatters(styleCodes: number[]): void {
 		for (let code of styleCodes) {
 			switch (code) {
-				case 0: {
+				case 0: {  // reset (everything)
 					styleNames = [];
 					customFgColor = undefined;
 					customBgColor = undefined;
 					break;
 				}
-				case 1: {
+				case 1: { // bold
+					styleNames = styleNames.filter(style => style !== `code-bold`);
 					styleNames.push('code-bold');
 					break;
 				}
-				case 3: {
+				case 2: { // dim
+					styleNames = styleNames.filter(style => style !== `code-dim`);
+					styleNames.push('code-dim');
+					break;
+				}
+				case 3: { // italic
+					styleNames = styleNames.filter(style => style !== `code-italic`);
 					styleNames.push('code-italic');
 					break;
 				}
-				case 4: {
+				case 4: { // underline
+					styleNames = styleNames.filter(style => (style !== `code-underline` && style !== `code-double-underline`));
 					styleNames.push('code-underline');
 					break;
 				}
-				case 39: {
+				case 5: { // blink
+					styleNames = styleNames.filter(style => style !== `code-blink`);
+					styleNames.push('code-blink');
+					break;
+				}
+				case 6: { // rapid blink
+					styleNames = styleNames.filter(style => style !== `code-rapid-blink`);
+					styleNames.push('code-rapid-blink');
+					break;
+				}
+				case 7: { // invert foreground and background
+					if (!colorsInverted) {
+						colorsInverted = true;
+						reverseForegroundAndBackgroundColors();
+					}
+					break;
+				}
+				case 8: { // hidden
+					styleNames = styleNames.filter(style => style !== `code-hidden`);
+					styleNames.push('code-hidden');
+					break;
+				}
+				case 9: { // strike-through/crossed-out
+					styleNames = styleNames.filter(style => style !== `code-strike-through`);
+					styleNames.push('code-strike-through');
+					break;
+				}
+				case 10: { // normal default font
+					styleNames = styleNames.filter(style => !style.startsWith('code-font'));
+					break;
+				}
+				case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: { // font codes (and 20 is 'blackletter' font code)
+					styleNames = styleNames.filter(style => !style.startsWith('code-font'));
+					styleNames.push(`code-font-${code - 10}`);
+					break;
+				}
+				case 21: { // double underline
+					styleNames = styleNames.filter(style => (style !== `code-underline` && style !== `code-double-underline`));
+					styleNames.push('code-double-underline');
+					break;
+				}
+				case 22: { // normal intensity (bold off and dim off)
+					styleNames = styleNames.filter(style => (style !== `code-bold` && style !== `code-dim`));
+					break;
+				}
+				case 23: { // Neither italic or blackletter (font 10)
+					styleNames = styleNames.filter(style => (style !== `code-italic` && style !== `code-font-10`));
+					break;
+				}
+				case 24: { // not underlined (Neither singly nor doubly underlined)
+					styleNames = styleNames.filter(style => (style !== `code-underline` && style !== `code-double-underline`));
+					break;
+				}
+				case 25: { // not blinking
+					styleNames = styleNames.filter(style => (style !== `code-blink` && style !== `code-rapid-blink`));
+					break;
+				}
+				case 27: { // not reversed/inverted
+					if (colorsInverted) {
+						colorsInverted = false;
+						reverseForegroundAndBackgroundColors();
+					}
+					break;
+				}
+				case 28: { // not hidden (reveal)
+					styleNames = styleNames.filter(style => style !== `code-hidden`);
+					break;
+				}
+				case 29: { // not crossed-out
+					styleNames = styleNames.filter(style => style !== `code-strike-through`);
+					break;
+				}
+				case 53: { // overlined
+					styleNames = styleNames.filter(style => style !== `code-overline`);
+					styleNames.push('code-overline');
+					break;
+				}
+				case 55: { // not overlined
+					styleNames = styleNames.filter(style => style !== `code-overline`);
+					break;
+				}
+				case 39: {  // default foreground color
 					changeColor('foreground', undefined);
 					break;
 				}
-				case 49: {
+				case 49: {  // default background color
 					changeColor('background', undefined);
 					break;
 				}
+				case 59: {  // default underline color
+					changeColor('underline', undefined);
+					break;
+				}
+				case 73: { // superscript
+					styleNames = styleNames.filter(style => (style !== `code-superscript` && style !== `code-subscript`));
+					styleNames.push('code-superscript');
+					break;
+				}
+				case 74: { // subscript
+					styleNames = styleNames.filter(style => (style !== `code-superscript` && style !== `code-subscript`));
+					styleNames.push('code-subscript');
+					break;
+				}
+				case 75: { // neither superscript or subscript
+					styleNames = styleNames.filter(style => (style !== `code-superscript` && style !== `code-subscript`));
+					break;
+				}
 				default: {
 					setBasicColor(code);
 					break;
@@ -177,10 +303,11 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 	 * @param styleCodes Full list of integer codes that make up the full ANSI
 	 * sequence, including the two defining codes and the three RGB codes.
 	 * @param colorType If `'foreground'`, will set foreground color, if
-	 * `'background'`, will set background color.
+	 * `'background'`, will set background color, and if it is `'underline'`
+	 * will set the underline color.
 	 * @see {@link https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit }
 	 */
-	function set24BitColor(styleCodes: number[], colorType: 'foreground' | 'background'): void {
+	function set24BitColor(styleCodes: number[], colorType: 'foreground' | 'background' | 'underline'): void {
 		if (styleCodes.length >= 5 &&
 			styleCodes[2] >= 0 && styleCodes[2] <= 255 &&
 			styleCodes[3] >= 0 && styleCodes[3] <= 255 &&
@@ -195,16 +322,27 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
 	 * @param styleCodes Full list of integer codes that make up the ANSI
 	 * sequence, including the two defining codes and the one color code.
 	 * @param colorType If `'foreground'`, will set foreground color, if
-	 * `'background'`, will set background color.
+	 * `'background'`, will set background color and if it is `'underline'`
+	 * will set the underline color.
 	 * @see {@link https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit }
 	 */
-	function set8BitColor(styleCodes: number[], colorType: 'foreground' | 'background'): void {
+	function set8BitColor(styleCodes: number[], colorType: 'foreground' | 'background' | 'underline'): void {
 		let colorNumber = styleCodes[2];
 		const color = calcANSI8bitColor(colorNumber);
 
 		if (color) {
 			changeColor(colorType, color);
 		} else if (colorNumber >= 0 && colorNumber <= 15) {
+			if (colorType === 'underline') {
+				// for underline colors we just decode the 0-15 color number to theme color, set and return
+				const theme = themeService.getColorTheme();
+				const colorName = ansiColorIdentifiers[colorNumber];
+				const color = theme.getColor(colorName);
+				if (color) {
+					changeColor(colorType, color.rgba);
+				}
+				return;
+			}
 			// Need to map to one of the four basic color ranges (30-37, 90-97, 40-47, 100-107)
 			colorNumber += 30;
 			if (colorNumber >= 38) {
@@ -261,7 +399,8 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme
  * @param cssClasses The list of CSS styles to apply to the text content.
  * @param linkDetector The {@link LinkDetector} responsible for generating links from {@param stringContent}.
  * @param customTextColor If provided, will apply custom color with inline style.
- * @param customBackgroundColor If provided, will apply custom color with inline style.
+ * @param customBackgroundColor If provided, will apply custom backgroundColor with inline style.
+ * @param customUnderlineColor If provided, will apply custom textDecorationColor with inline style.
  */
 export function appendStylizedStringToContainer(
 	root: HTMLElement,
@@ -270,7 +409,8 @@ export function appendStylizedStringToContainer(
 	linkDetector: LinkDetector,
 	workspaceFolder: IWorkspaceFolder | undefined,
 	customTextColor?: RGBA,
-	customBackgroundColor?: RGBA
+	customBackgroundColor?: RGBA,
+	customUnderlineColor?: RGBA
 ): void {
 	if (!root || !stringContent) {
 		return;
@@ -287,7 +427,10 @@ export function appendStylizedStringToContainer(
 		container.style.backgroundColor =
 			Color.Format.CSS.formatRGB(new Color(customBackgroundColor));
 	}
-
+	if (customUnderlineColor) {
+		container.style.textDecorationColor =
+			Color.Format.CSS.formatRGB(new Color(customUnderlineColor));
+	}
 	root.appendChild(container);
 }
 
diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css
--- a/src/vs/workbench/contrib/debug/browser/media/repl.css
+++ b/src/vs/workbench/contrib/debug/browser/media/repl.css
@@ -102,7 +102,27 @@
 /* ANSI Codes */
 .monaco-workbench .repl .repl-tree .output.expression .code-bold	{ font-weight: bold; }
 .monaco-workbench .repl .repl-tree .output.expression .code-italic	{ font-style: italic; }
-.monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; }
+.monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline;  text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-double-underline { text-decoration: underline;  text-decoration-style:double; }
+.monaco-workbench .repl .repl-tree .output.expression .code-strike-through { text-decoration:line-through;  text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-overline { text-decoration:overline;  text-decoration-style:solid; }
+/* because they can exist at same time we need all the possible underline(or double-underline),overline and strike-through combinations */
+.monaco-workbench .repl .repl-tree .output.expression .code-overline.code-underline.code-strike-through { text-decoration: overline underline line-through; text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-overline.code-underline { text-decoration: overline underline; text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-overline.code-strike-through { text-decoration: overline line-through; text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-underline.code-strike-through { text-decoration: underline line-through; text-decoration-style:solid; }
+.monaco-workbench .repl .repl-tree .output.expression .code-overline.code-double-underline.code-strike-through { text-decoration: overline underline line-through; text-decoration-style:double; }
+.monaco-workbench .repl .repl-tree .output.expression .code-overline.code-double-underline { text-decoration: overline underline; text-decoration-style:double; }
+.monaco-workbench .repl .repl-tree .output.expression .code-double-underline.code-strike-through { text-decoration: underline line-through; text-decoration-style:double; }
+.monaco-workbench .repl .repl-tree .output.expression .code-dim	{ opacity: 0.4; }
+.monaco-workbench .repl .repl-tree .output.expression .code-hidden { opacity: 0; }
+.monaco-workbench .repl .repl-tree .output.expression .code-blink { animation: code-blink-key 1s cubic-bezier(1, 0, 0, 1) infinite alternate; }
+.monaco-workbench .repl .repl-tree .output.expression .code-rapid-blink { animation: code-blink-key 0.3s cubic-bezier(1, 0, 0, 1) infinite alternate; }
+@keyframes code-blink-key {
+	to { opacity: 0.4; }
+}
+.monaco-workbench .repl .repl-tree .output.expression .code-subscript { vertical-align: sub; font-size: smaller; line-height: normal; }
+.monaco-workbench .repl .repl-tree .output.expression .code-superscript { vertical-align: super; font-size: smaller; line-height: normal; }
 
 .monaco-action-bar .action-item.repl-panel-filter-container {
 	cursor: default;


Test patch:
diff --git a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts
--- a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts
+++ b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts
@@ -110,11 +110,15 @@ suite('Debug - ANSI Handling', () => {
 	 * @param element The HTML span element to look at.
 	 * @param colorType If `foreground`, will check the element's css `color`;
 	 * if `background`, will check the element's css `backgroundColor`.
+	 * if `underline`, will check the elements css `textDecorationColor`.
 	 * @param color RGBA object to compare color to. If `undefined` or not provided,
 	 * will assert that no value is set.
 	 * @param message Optional custom message to pass to assertion.
+	 * @param colorShouldMatch Optional flag (defaults TO true) which allows caller to indicate that the color SHOULD NOT MATCH
+	 * (for testing changes to theme colors where we need color to have changed but we don't know exact color it should have
+	 * changed to (but we do know the color it should NO LONGER BE))
 	 */
-	function assertInlineColor(element: HTMLSpanElement, colorType: 'background' | 'foreground', color?: RGBA | undefined, message?: string): void {
+	function assertInlineColor(element: HTMLSpanElement, colorType: 'background' | 'foreground' | 'underline', color?: RGBA | undefined, message?: string, colorShouldMatch: boolean = true): void {
 		if (color !== undefined) {
 			const cssColor = Color.Format.CSS.formatRGB(
 				new Color(color)
@@ -122,17 +126,23 @@ suite('Debug - ANSI Handling', () => {
 			if (colorType === 'background') {
 				const styleBefore = element.style.backgroundColor;
 				element.style.backgroundColor = cssColor;
-				assert(styleBefore === element.style.backgroundColor, message || `Incorrect ${colorType} color style found (found color: ${styleBefore}, expected ${cssColor}).`);
-			} else {
+				assert((styleBefore === element.style.backgroundColor) === colorShouldMatch, message || `Incorrect ${colorType} color style found (found color: ${styleBefore}, expected ${cssColor}).`);
+			} else if (colorType === 'foreground') {
 				const styleBefore = element.style.color;
 				element.style.color = cssColor;
-				assert(styleBefore === element.style.color, message || `Incorrect ${colorType} color style found (found color: ${styleBefore}, expected ${cssColor}).`);
+				assert((styleBefore === element.style.color) === colorShouldMatch, message || `Incorrect ${colorType} color style found (found color: ${styleBefore}, expected ${cssColor}).`);
+			} else {
+				const styleBefore = element.style.textDecorationColor;
+				element.style.textDecorationColor = cssColor;
+				assert((styleBefore === element.style.textDecorationColor) === colorShouldMatch, message || `Incorrect ${colorType} color style found (found color: ${styleBefore}, expected ${cssColor}).`);
 			}
 		} else {
 			if (colorType === 'background') {
 				assert(!element.style.backgroundColor, message || `Defined ${colorType} color style found when it should not have been defined`);
-			} else {
+			} else if (colorType === 'foreground') {
 				assert(!element.style.color, message || `Defined ${colorType} color style found when it should not have been defined`);
+			} else {
+				assert(!element.style.textDecorationColor, message || `Defined ${colorType} color style found when it should not have been defined`);
 			}
 		}
 
@@ -185,6 +195,22 @@ suite('Debug - ANSI Handling', () => {
 			});
 		}
 
+		// check all basic colors for underlines (full range is checked elsewhere, here we check cancelation)
+		for (let i = 0; i <= 255; i++) {
+			const customClassName: string = 'code-underline-colored';
+
+			// Underline colour class
+			assertSingleSequenceElement('\x1b[58;5;' + i + 'm', (child) => {
+				assert(child.classList.contains(customClassName), `Custom underline color class not found on element after underline color ANSI code 58;5;${i}m.`);
+			});
+
+			// Cancellation underline color code removes colour class
+			assertSingleSequenceElement('\x1b[58;5;' + i + 'm\x1b[59m', (child) => {
+				assert(child.classList.contains(customClassName) === false, 'Custom underline color class still found after underline color cancellation code 59m.');
+				assertInlineColor(child, 'underline', undefined, 'Custom underline color style still found after underline color cancellation code 59m.');
+			});
+		}
+
 		// Different codes do not cancel each other
 		assertSingleSequenceElement('\x1b[1;3;4;30;41m', (child) => {
 			assert.strictEqual(5, child.classList.length, 'Incorrect number of classes found for different ANSI codes.');
@@ -196,6 +222,41 @@ suite('Debug - ANSI Handling', () => {
 			assert(child.classList.contains('code-background-colored'), 'Different ANSI codes should not cancel each other.');
 		});
 
+		// Different codes do not ACCUMULATE more than one copy of each class
+		assertSingleSequenceElement('\x1b[1;1;2;2;3;3;4;4;5;5;6;6;8;8;9;9;21;21;53;53;73;73;74;74m', (child) => {
+			assert(child.classList.contains('code-bold'));
+			assert(child.classList.contains('code-italic'), 'italic missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-underline') === false, 'underline PRESENT and double underline should have removed it- Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-dim'), 'dim missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-blink'), 'blink missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-rapid-blink'), 'rapid blink mkssing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-double-underline'), 'double underline missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-hidden'), 'hidden missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-strike-through'), 'strike-through missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-overline'), 'overline missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-superscript') === false, 'superscript PRESENT and subscript should have removed it- Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+			assert(child.classList.contains('code-subscript'), 'subscript missing Doubles of each Different ANSI codes should not cancel each other or accumulate.');
+
+			assert.strictEqual(10, child.classList.length, 'Incorrect number of classes found for each style code sent twice ANSI codes.');
+		});
+
+
+
+		// More Different codes do not cancel each other
+		assertSingleSequenceElement('\x1b[1;2;5;6;21;8;9m', (child) => {
+			assert.strictEqual(7, child.classList.length, 'Incorrect number of classes found for different ANSI codes.');
+
+			assert(child.classList.contains('code-bold'));
+			assert(child.classList.contains('code-dim'), 'Different ANSI codes should not cancel each other.');
+			assert(child.classList.contains('code-blink'), 'Different ANSI codes should not cancel each other.');
+			assert(child.classList.contains('code-rapid-blink'), 'Different ANSI codes should not cancel each other.');
+			assert(child.classList.contains('code-double-underline'), 'Different ANSI codes should not cancel each other.');
+			assert(child.classList.contains('code-hidden'), 'Different ANSI codes should not cancel each other.');
+			assert(child.classList.contains('code-strike-through'), 'Different ANSI codes should not cancel each other.');
+		});
+
+
+
 		// New foreground codes don't remove old background codes and vice versa
 		assertSingleSequenceElement('\x1b[40;31;42;33m', (child) => {
 			assert.strictEqual(2, child.classList.length);
@@ -253,6 +314,12 @@ suite('Debug - ANSI Handling', () => {
 				assert(child.classList.contains('code-background-colored'), `Custom color class not found after background 8-bit color code 48;5;${i}`);
 				assertInlineColor(child, 'background', (calcANSI8bitColor(i) as RGBA), `Incorrect or no color styling found after background 8-bit color code 48;5;${i}`);
 			});
+
+			// Color underline codes should add custom class and inline style
+			assertSingleSequenceElement('\x1b[58;5;' + i + 'm', (child) => {
+				assert(child.classList.contains('code-underline-colored'), `Custom color class not found after underline 8-bit color code 58;5;${i}`);
+				assertInlineColor(child, 'underline', (calcANSI8bitColor(i) as RGBA), `Incorrect or no color styling found after underline 8-bit color code 58;5;${i}`);
+			});
 		}
 
 		// Bad (nonexistent) color should not render
@@ -285,6 +352,12 @@ suite('Debug - ANSI Handling', () => {
 						assert(child.classList.contains('code-background-colored'), 'DOM should have "code-foreground-colored" class for advanced ANSI colors.');
 						assertInlineColor(child, 'background', color);
 					});
+
+					// Underline color codes should add class and inline style
+					assertSingleSequenceElement(`\x1b[58;2;${r};${g};${b}m`, (child) => {
+						assert(child.classList.contains('code-underline-colored'), 'DOM should have "code-underline-colored" class for advanced ANSI colors.');
+						assertInlineColor(child, 'underline', color);
+					});
 				}
 			}
 		}
@@ -371,8 +444,474 @@ suite('Debug - ANSI Handling', () => {
 			},
 		], 5);
 
+		// Consecutive codes with ENDING/OFF codes do not LEAVE affect previous ones
+		assertMultipleSequenceElements('\x1b[1mbold\x1b[22m\x1b[32mgreen\x1b[4munderline\x1b[24m\x1b[3mitalic\x1b[23mjustgreen\x1b[0mnothing', [
+			(bold) => {
+				assert.strictEqual(1, bold.classList.length);
+				assert(bold.classList.contains('code-bold'), 'Bold class not found after bold ANSI code.');
+			},
+			(green) => {
+				assert.strictEqual(1, green.classList.length);
+				assert(green.classList.contains('code-bold') === false, 'Bold class found after both bold WAS TURNED OFF with 22m');
+				assert(green.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(underline) => {
+				assert.strictEqual(2, underline.classList.length);
+				assert(underline.classList.contains('code-foreground-colored'), 'Color class not found after color and underline ANSI codes.');
+				assert(underline.classList.contains('code-underline'), 'Underline class not found after underline ANSI code.');
+			},
+			(italic) => {
+				assert.strictEqual(2, italic.classList.length);
+				assert(italic.classList.contains('code-foreground-colored'), 'Color class not found after color, underline, and italic ANSI codes.');
+				assert(italic.classList.contains('code-underline') === false, 'Underline class found after underline WAS TURNED OFF with 24m');
+				assert(italic.classList.contains('code-italic'), 'Italic class not found after italic ANSI code.');
+			},
+			(justgreen) => {
+				assert.strictEqual(1, justgreen.classList.length);
+				assert(justgreen.classList.contains('code-italic') === false, 'Italic class found after italic WAS TURNED OFF with 23m');
+				assert(justgreen.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after reset ANSI code.');
+			},
+		], 6);
+
+		// more Consecutive codes with ENDING/OFF codes do not LEAVE affect previous ones
+		assertMultipleSequenceElements('\x1b[2mdim\x1b[22m\x1b[32mgreen\x1b[5mslowblink\x1b[25m\x1b[6mrapidblink\x1b[25mjustgreen\x1b[0mnothing', [
+			(dim) => {
+				assert.strictEqual(1, dim.classList.length);
+				assert(dim.classList.contains('code-dim'), 'Dim class not found after dim ANSI code 2m.');
+			},
+			(green) => {
+				assert.strictEqual(1, green.classList.length);
+				assert(green.classList.contains('code-dim') === false, 'Dim class found after dim WAS TURNED OFF with 22m');
+				assert(green.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(slowblink) => {
+				assert.strictEqual(2, slowblink.classList.length);
+				assert(slowblink.classList.contains('code-foreground-colored'), 'Color class not found after color and blink ANSI codes.');
+				assert(slowblink.classList.contains('code-blink'), 'Blink class not found after underline ANSI code 5m.');
+			},
+			(rapidblink) => {
+				assert.strictEqual(2, rapidblink.classList.length);
+				assert(rapidblink.classList.contains('code-foreground-colored'), 'Color class not found after color, blink, and rapid blink ANSI codes.');
+				assert(rapidblink.classList.contains('code-blink') === false, 'blink class found after underline WAS TURNED OFF with 25m');
+				assert(rapidblink.classList.contains('code-rapid-blink'), 'Rapid blink class not found after rapid blink ANSI code 6m.');
+			},
+			(justgreen) => {
+				assert.strictEqual(1, justgreen.classList.length);
+				assert(justgreen.classList.contains('code-rapid-blink') === false, 'Rapid blink class found after rapid blink WAS TURNED OFF with 25m');
+				assert(justgreen.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after reset ANSI code.');
+			},
+		], 6);
+
+		// more Consecutive codes with ENDING/OFF codes do not LEAVE affect previous ones
+		assertMultipleSequenceElements('\x1b[8mhidden\x1b[28m\x1b[32mgreen\x1b[9mcrossedout\x1b[29m\x1b[21mdoubleunderline\x1b[24mjustgreen\x1b[0mnothing', [
+			(hidden) => {
+				assert.strictEqual(1, hidden.classList.length);
+				assert(hidden.classList.contains('code-hidden'), 'Hidden class not found after dim ANSI code 8m.');
+			},
+			(green) => {
+				assert.strictEqual(1, green.classList.length);
+				assert(green.classList.contains('code-hidden') === false, 'Hidden class found after Hidden WAS TURNED OFF with 28m');
+				assert(green.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(crossedout) => {
+				assert.strictEqual(2, crossedout.classList.length);
+				assert(crossedout.classList.contains('code-foreground-colored'), 'Color class not found after color and hidden ANSI codes.');
+				assert(crossedout.classList.contains('code-strike-through'), 'strike-through class not found after crossout/strikethrough ANSI code 9m.');
+			},
+			(doubleunderline) => {
+				assert.strictEqual(2, doubleunderline.classList.length);
+				assert(doubleunderline.classList.contains('code-foreground-colored'), 'Color class not found after color, hidden, and crossedout ANSI codes.');
+				assert(doubleunderline.classList.contains('code-strike-through') === false, 'strike-through class found after strike-through WAS TURNED OFF with 29m');
+				assert(doubleunderline.classList.contains('code-double-underline'), 'Double underline class not found after double underline ANSI code 21m.');
+			},
+			(justgreen) => {
+				assert.strictEqual(1, justgreen.classList.length);
+				assert(justgreen.classList.contains('code-double-underline') === false, 'Double underline class found after double underline WAS TURNED OFF with 24m');
+				assert(justgreen.classList.contains('code-foreground-colored'), 'Color class not found after color ANSI code.');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after reset ANSI code.');
+			},
+		], 6);
+
+		// underline, double underline are mutually exclusive, test underline->double underline->off and double underline->underline->off
+		assertMultipleSequenceElements('\x1b[4munderline\x1b[21mdouble underline\x1b[24munderlineOff\x1b[21mdouble underline\x1b[4munderline\x1b[24munderlineOff', [
+			(underline) => {
+				assert.strictEqual(1, underline.classList.length);
+				assert(underline.classList.contains('code-underline'), 'Underline class not found after underline ANSI code 4m.');
+			},
+			(doubleunderline) => {
+				assert(doubleunderline.classList.contains('code-underline') === false, 'Underline class found after double underline code 21m');
+				assert(doubleunderline.classList.contains('code-double-underline'), 'Double underline class not found after double underline code 21m');
+				assert.strictEqual(1, doubleunderline.classList.length, 'should have found only double underline');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after underline off code 4m.');
+			},
+			(doubleunderline) => {
+				assert(doubleunderline.classList.contains('code-double-underline'), 'Double underline class not found after double underline code 21m');
+				assert.strictEqual(1, doubleunderline.classList.length, 'should have found only double underline');
+			},
+			(underline) => {
+				assert(underline.classList.contains('code-double-underline') === false, 'Double underline class found after underline code 4m');
+				assert(underline.classList.contains('code-underline'), 'Underline class not found after underline ANSI code 4m.');
+				assert.strictEqual(1, underline.classList.length, 'should have found only underline');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after underline off code 4m.');
+			},
+		], 6);
+
+		// underline and strike-through and overline can exist at the same time and
+		// in any combination
+		assertMultipleSequenceElements('\x1b[4munderline\x1b[9mand strikethough\x1b[53mand overline\x1b[24munderlineOff\x1b[55moverlineOff\x1b[29mstriklethoughOff', [
+			(underline) => {
+				assert.strictEqual(1, underline.classList.length, 'should have found only underline');
+				assert(underline.classList.contains('code-underline'), 'Underline class not found after underline ANSI code 4m.');
+			},
+			(strikethrough) => {
+				assert(strikethrough.classList.contains('code-underline'), 'Underline class NOT found after strikethrough code 9m');
+				assert(strikethrough.classList.contains('code-strike-through'), 'Strike through class not found after strikethrough code 9m');
+				assert.strictEqual(2, strikethrough.classList.length, 'should have found underline and strikethrough');
+			},
+			(overline) => {
+				assert(overline.classList.contains('code-underline'), 'Underline class NOT found after overline code 53m');
+				assert(overline.classList.contains('code-strike-through'), 'Strike through class not found after overline code 53m');
+				assert(overline.classList.contains('code-overline'), 'Overline class not found after overline code 53m');
+				assert.strictEqual(3, overline.classList.length, 'should have found underline,strikethrough and overline');
+			},
+			(underlineoff) => {
+				assert(underlineoff.classList.contains('code-underline') === false, 'Underline class found after underline off code 24m');
+				assert(underlineoff.classList.contains('code-strike-through'), 'Strike through class not found after underline off code 24m');
+				assert(underlineoff.classList.contains('code-overline'), 'Overline class not found after underline off code 24m');
+				assert.strictEqual(2, underlineoff.classList.length, 'should have found strikethrough and overline');
+			},
+			(overlineoff) => {
+				assert(overlineoff.classList.contains('code-underline') === false, 'Underline class found after overline off code 55m');
+				assert(overlineoff.classList.contains('code-overline') === false, 'Overline class found after overline off code 55m');
+				assert(overlineoff.classList.contains('code-strike-through'), 'Strike through class not found after overline off code 55m');
+				assert.strictEqual(1, overlineoff.classList.length, 'should have found only strikethrough');
+			},
+			(nothing) => {
+				assert(nothing.classList.contains('code-strike-through') === false, 'Strike through class found after strikethrough off code 29m');
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after strikethough OFF code 29m');
+			},
+		], 6);
+
+		// double underline and strike-through and overline can exist at the same time and
+		// in any combination
+		assertMultipleSequenceElements('\x1b[21mdoubleunderline\x1b[9mand strikethough\x1b[53mand overline\x1b[29mstriklethoughOff\x1b[55moverlineOff\x1b[24munderlineOff', [
+			(doubleunderline) => {
+				assert.strictEqual(1, doubleunderline.classList.length, 'should have found only doubleunderline');
+				assert(doubleunderline.classList.contains('code-double-underline'), 'Double underline class not found after double underline ANSI code 21m.');
+			},
+			(strikethrough) => {
+				assert(strikethrough.classList.contains('code-double-underline'), 'Double nderline class NOT found after strikethrough code 9m');
+				assert(strikethrough.classList.contains('code-strike-through'), 'Strike through class not found after strikethrough code 9m');
+				assert.strictEqual(2, strikethrough.classList.length, 'should have found doubleunderline and strikethrough');
+			},
+			(overline) => {
+				assert(overline.classList.contains('code-double-underline'), 'Double underline class NOT found after overline code 53m');
+				assert(overline.classList.contains('code-strike-through'), 'Strike through class not found after overline code 53m');
+				assert(overline.classList.contains('code-overline'), 'Overline class not found after overline code 53m');
+				assert.strictEqual(3, overline.classList.length, 'should have found doubleunderline,overline and strikethrough');
+			},
+			(strikethrougheoff) => {
+				assert(strikethrougheoff.classList.contains('code-double-underline'), 'Double underline class NOT found after strikethrough off code 29m');
+				assert(strikethrougheoff.classList.contains('code-overline'), 'Overline class NOT found after strikethrough off code 29m');
+				assert(strikethrougheoff.classList.contains('code-strike-through') === false, 'Strike through class found after strikethrough off code 29m');
+				assert.strictEqual(2, strikethrougheoff.classList.length, 'should have found doubleunderline and overline');
+			},
+			(overlineoff) => {
+				assert(overlineoff.classList.contains('code-double-underline'), 'Double underline class NOT found after overline off code 55m');
+				assert(overlineoff.classList.contains('code-strike-through') === false, 'Strike through class found after overline off code 55m');
+				assert(overlineoff.classList.contains('code-overline') === false, 'Overline class found after overline off code 55m');
+				assert.strictEqual(1, overlineoff.classList.length, 'Should have found only double underline');
+			},
+			(nothing) => {
+				assert(nothing.classList.contains('code-double-underline') === false, 'Double underline class found after underline off code 24m');
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after underline OFF code 24m');
+			},
+		], 6);
+
+		// superscript and subscript are mutually exclusive, test superscript->subscript->off and subscript->superscript->off
+		assertMultipleSequenceElements('\x1b[73msuperscript\x1b[74msubscript\x1b[75mneither\x1b[74msubscript\x1b[73msuperscript\x1b[75mneither', [
+			(superscript) => {
+				assert.strictEqual(1, superscript.classList.length, 'should only be superscript class');
+				assert(superscript.classList.contains('code-superscript'), 'Superscript class not found after superscript ANSI code 73m.');
+			},
+			(subscript) => {
+				assert(subscript.classList.contains('code-superscript') === false, 'Superscript class found after subscript code 74m');
+				assert(subscript.classList.contains('code-subscript'), 'Subscript class not found after subscript code 74m');
+				assert.strictEqual(1, subscript.classList.length, 'should have found only subscript class');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after superscript/subscript off code 75m.');
+			},
+			(subscript) => {
+				assert(subscript.classList.contains('code-subscript'), 'Subscript class not found after subscript code 74m');
+				assert.strictEqual(1, subscript.classList.length, 'should have found only subscript class');
+			},
+			(superscript) => {
+				assert(superscript.classList.contains('code-subscript') === false, 'Subscript class found after superscript code 73m');
+				assert(superscript.classList.contains('code-superscript'), 'Superscript class not found after superscript ANSI code 73m.');
+				assert.strictEqual(1, superscript.classList.length, 'should have found only superscript class');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more style classes still found after superscipt/subscript off code 75m.');
+			},
+		], 6);
+
+		// Consecutive font codes switch to new font class and remove previous and then final switch to default font removes class
+		assertMultipleSequenceElements('\x1b[11mFont1\x1b[12mFont2\x1b[13mFont3\x1b[14mFont4\x1b[15mFont5\x1b[10mdefaultFont', [
+			(font1) => {
+				assert.strictEqual(1, font1.classList.length);
+				assert(font1.classList.contains('code-font-1'), 'font 1 class NOT found after switch to font 1 with ANSI code 11m');
+			},
+			(font2) => {
+				assert.strictEqual(1, font2.classList.length);
+				assert(font2.classList.contains('code-font-1') === false, 'font 1 class found after switch to font 2 with ANSI code 12m');
+				assert(font2.classList.contains('code-font-2'), 'font 2 class NOT found after switch to font 2 with ANSI code 12m');
+			},
+			(font3) => {
+				assert.strictEqual(1, font3.classList.length);
+				assert(font3.classList.contains('code-font-2') === false, 'font 2 class found after switch to font 3 with ANSI code 13m');
+				assert(font3.classList.contains('code-font-3'), 'font 3 class NOT found after switch to font 3 with ANSI code 13m');
+			},
+			(font4) => {
+				assert.strictEqual(1, font4.classList.length);
+				assert(font4.classList.contains('code-font-3') === false, 'font 3 class found after switch to font 4 with ANSI code 14m');
+				assert(font4.classList.contains('code-font-4'), 'font 4 class NOT found after switch to font 4 with ANSI code 14m');
+			},
+			(font5) => {
+				assert.strictEqual(1, font5.classList.length);
+				assert(font5.classList.contains('code-font-4') === false, 'font 4 class found after switch to font 5 with ANSI code 15m');
+				assert(font5.classList.contains('code-font-5'), 'font 5 class NOT found after switch to font 5 with ANSI code 15m');
+			},
+			(defaultfont) => {
+				assert.strictEqual(0, defaultfont.classList.length, 'One or more font style classes still found after reset to default font with ANSI code 10m.');
+			},
+		], 6);
+
+		// More Consecutive font codes switch to new font class and remove previous and then final switch to default font removes class
+		assertMultipleSequenceElements('\x1b[16mFont6\x1b[17mFont7\x1b[18mFont8\x1b[19mFont9\x1b[20mFont10\x1b[10mdefaultFont', [
+			(font6) => {
+				assert.strictEqual(1, font6.classList.length);
+				assert(font6.classList.contains('code-font-6'), 'font 6 class NOT found after switch to font 6 with ANSI code 16m');
+			},
+			(font7) => {
+				assert.strictEqual(1, font7.classList.length);
+				assert(font7.classList.contains('code-font-6') === false, 'font 6 class found after switch to font 7 with ANSI code 17m');
+				assert(font7.classList.contains('code-font-7'), 'font 7 class NOT found after switch to font 7 with ANSI code 17m');
+			},
+			(font8) => {
+				assert.strictEqual(1, font8.classList.length);
+				assert(font8.classList.contains('code-font-7') === false, 'font 7 class found after switch to font 8 with ANSI code 18m');
+				assert(font8.classList.contains('code-font-8'), 'font 8 class NOT found after switch to font 8 with ANSI code 18m');
+			},
+			(font9) => {
+				assert.strictEqual(1, font9.classList.length);
+				assert(font9.classList.contains('code-font-8') === false, 'font 8 class found after switch to font 9 with ANSI code 19m');
+				assert(font9.classList.contains('code-font-9'), 'font 9 class NOT found after switch to font 9 with ANSI code 19m');
+			},
+			(font10) => {
+				assert.strictEqual(1, font10.classList.length);
+				assert(font10.classList.contains('code-font-9') === false, 'font 9 class found after switch to font 10 with ANSI code 20m');
+				assert(font10.classList.contains('code-font-10'), `font 10 class NOT found after switch to font 10 with ANSI code 20m (${font10.classList})`);
+			},
+			(defaultfont) => {
+				assert.strictEqual(0, defaultfont.classList.length, 'One or more font style classes (2nd series) still found after reset to default font with ANSI code 10m.');
+			},
+		], 6);
+
+		// Blackletter font codes can be turned off with other font codes or 23m
+		assertMultipleSequenceElements('\x1b[3mitalic\x1b[20mfont10blacklatter\x1b[23mitalicAndBlackletterOff\x1b[20mFont10Again\x1b[11mFont1\x1b[10mdefaultFont', [
+			(italic) => {
+				assert.strictEqual(1, italic.classList.length);
+				assert(italic.classList.contains('code-italic'), 'italic class NOT found after italic code ANSI code 3m');
+			},
+			(font10) => {
+				assert.strictEqual(2, font10.classList.length);
+				assert(font10.classList.contains('code-italic'), 'no itatic class found after switch to font 10 (blackletter) with ANSI code 20m');
+				assert(font10.classList.contains('code-font-10'), 'font 10 class NOT found after switch to font 10 with ANSI code 20m');
+			},
+			(italicAndBlackletterOff) => {
+				assert.strictEqual(0, italicAndBlackletterOff.classList.length, 'italic or blackletter (font10) class found after both switched off with ANSI code 23m');
+			},
+			(font10) => {
+				assert.strictEqual(1, font10.classList.length);
+				assert(font10.classList.contains('code-font-10'), 'font 10 class NOT found after switch to font 10 with ANSI code 20m');
+			},
+			(font1) => {
+				assert.strictEqual(1, font1.classList.length);
+				assert(font1.classList.contains('code-font-10') === false, 'font 10 class found after switch to font 1 with ANSI code 11m');
+				assert(font1.classList.contains('code-font-1'), 'font 1 class NOT found after switch to font 1 with ANSI code 11m');
+			},
+			(defaultfont) => {
+				assert.strictEqual(0, defaultfont.classList.length, 'One or more font style classes (2nd series) still found after reset to default font with ANSI code 10m.');
+			},
+		], 6);
+
+		// italic can be turned on/off with affecting font codes 1-9  (italic off will clear 'blackletter'(font 23) as per spec)
+		assertMultipleSequenceElements('\x1b[3mitalic\x1b[12mfont2\x1b[23mitalicOff\x1b[3mitalicFont2\x1b[10mjustitalic\x1b[23mnothing', [
+			(italic) => {
+				assert.strictEqual(1, italic.classList.length);
+				assert(italic.classList.contains('code-italic'), 'italic class NOT found after italic code ANSI code 3m');
+			},
+			(font10) => {
+				assert.strictEqual(2, font10.classList.length);
+				assert(font10.classList.contains('code-italic'), 'no itatic class found after switch to font 2 with ANSI code 12m');
+				assert(font10.classList.contains('code-font-2'), 'font 2 class NOT found after switch to font 2 with ANSI code 12m');
+			},
+			(italicOff) => {
+				assert.strictEqual(1, italicOff.classList.length, 'italic class found after both switched off with ANSI code 23m');
+				assert(italicOff.classList.contains('code-italic') === false, 'itatic class found after switching it OFF with ANSI code 23m');
+				assert(italicOff.classList.contains('code-font-2'), 'font 2 class NOT found after switching italic off with ANSI code 23m');
+			},
+			(italicFont2) => {
+				assert.strictEqual(2, italicFont2.classList.length);
+				assert(italicFont2.classList.contains('code-italic'), 'no itatic class found after italic ANSI code 3m');
+				assert(italicFont2.classList.contains('code-font-2'), 'font 2 class NOT found after italic ANSI code 3m');
+			},
+			(justitalic) => {
+				assert.strictEqual(1, justitalic.classList.length);
+				assert(justitalic.classList.contains('code-font-2') === false, 'font 2 class found after switch to default font with ANSI code 10m');
+				assert(justitalic.classList.contains('code-italic'), 'italic class NOT found after switch to default font with ANSI code 10m');
+			},
+			(nothing) => {
+				assert.strictEqual(0, nothing.classList.length, 'One or more classes still found after final italic removal with ANSI code 23m.');
+			},
+		], 6);
+
+		// Reverse video reverses Foreground/Background colors WITH both SET and can called in sequence
+		assertMultipleSequenceElements('\x1b[38;2;10;20;30mfg10,20,30\x1b[48;2;167;168;169mbg167,168,169\x1b[7m8ReverseVideo\x1b[7mDuplicateReverseVideo\x1b[27mReverseOff\x1b[27mDupReverseOff', [
+			(fg10_20_30) => {
+				assert.strictEqual(1, fg10_20_30.classList.length, 'Foreground ANSI color code should add one class.');
+				assert(fg10_20_30.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(fg10_20_30, 'foreground', new RGBA(10, 20, 30), '24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+			(bg167_168_169) => {
+				assert.strictEqual(2, bg167_168_169.classList.length, 'background ANSI color codes should only add a single class.');
+				assert(bg167_168_169.classList.contains('code-background-colored'), 'Background ANSI color codes should add custom background color class.');
+				assertInlineColor(bg167_168_169, 'background', new RGBA(167, 168, 169), '24-bit RGBA ANSI background color code (167,168,169) should add matching color inline style.');
+				assert(bg167_168_169.classList.contains('code-foreground-colored'), 'Still Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(bg167_168_169, 'foreground', new RGBA(10, 20, 30), 'Still 24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+			(reverseVideo) => {
+				assert.strictEqual(2, reverseVideo.classList.length, 'background ANSI color codes should only add a single class.');
+				assert(reverseVideo.classList.contains('code-background-colored'), 'Background ANSI color codes should add custom background color class.');
+				assertInlineColor(reverseVideo, 'foreground', new RGBA(167, 168, 169), 'Reversed 24-bit RGBA ANSI foreground color code (167,168,169) should add matching former background color inline style.');
+				assert(reverseVideo.classList.contains('code-foreground-colored'), 'Still Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(reverseVideo, 'background', new RGBA(10, 20, 30), 'Reversed 24-bit RGBA ANSI background color code (10,20,30) should add matching former foreground color inline style.');
+			},
+			(dupReverseVideo) => {
+				assert.strictEqual(2, dupReverseVideo.classList.length, 'After second Reverse Video - background ANSI color codes should only add a single class.');
+				assert(dupReverseVideo.classList.contains('code-background-colored'), 'After second Reverse Video - Background ANSI color codes should add custom background color class.');
+				assertInlineColor(dupReverseVideo, 'foreground', new RGBA(167, 168, 169), 'After second Reverse Video - Reversed 24-bit RGBA ANSI foreground color code (167,168,169) should add matching former background color inline style.');
+				assert(dupReverseVideo.classList.contains('code-foreground-colored'), 'After second Reverse Video - Still Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(dupReverseVideo, 'background', new RGBA(10, 20, 30), 'After second Reverse Video - Reversed 24-bit RGBA ANSI background color code (10,20,30) should add matching former foreground color inline style.');
+			},
+			(reversedBack) => {
+				assert.strictEqual(2, reversedBack.classList.length, 'Reversed Back - background ANSI color codes should only add a single class.');
+				assert(reversedBack.classList.contains('code-background-colored'), 'Reversed Back - Background ANSI color codes should add custom background color class.');
+				assertInlineColor(reversedBack, 'background', new RGBA(167, 168, 169), 'Reversed Back - 24-bit RGBA ANSI background color code (167,168,169) should add matching color inline style.');
+				assert(reversedBack.classList.contains('code-foreground-colored'), 'Reversed Back -  Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(reversedBack, 'foreground', new RGBA(10, 20, 30), 'Reversed Back -  24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+			(dupReversedBack) => {
+				assert.strictEqual(2, dupReversedBack.classList.length, '2nd Reversed Back - background ANSI color codes should only add a single class.');
+				assert(dupReversedBack.classList.contains('code-background-colored'), '2nd Reversed Back - Background ANSI color codes should add custom background color class.');
+				assertInlineColor(dupReversedBack, 'background', new RGBA(167, 168, 169), '2nd Reversed Back - 24-bit RGBA ANSI background color code (167,168,169) should add matching color inline style.');
+				assert(dupReversedBack.classList.contains('code-foreground-colored'), '2nd Reversed Back -  Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(dupReversedBack, 'foreground', new RGBA(10, 20, 30), '2nd Reversed Back -  24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+		], 6);
+
+		// Reverse video reverses Foreground/Background colors WITH ONLY foreground color SET
+		assertMultipleSequenceElements('\x1b[38;2;10;20;30mfg10,20,30\x1b[7m8ReverseVideo\x1b[27mReverseOff', [
+			(fg10_20_30) => {
+				assert.strictEqual(1, fg10_20_30.classList.length, 'Foreground ANSI color code should add one class.');
+				assert(fg10_20_30.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(fg10_20_30, 'foreground', new RGBA(10, 20, 30), '24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+			(reverseVideo) => {
+				assert.strictEqual(1, reverseVideo.classList.length, 'Background ANSI color codes should only add a single class.');
+				assert(reverseVideo.classList.contains('code-background-colored'), 'Background ANSI color codes should add custom background color class.');
+				assert(reverseVideo.classList.contains('code-foreground-colored') === false, 'After Reverse with NO background the Foreground ANSI color codes should NOT BE SET.');
+				assertInlineColor(reverseVideo, 'background', new RGBA(10, 20, 30), 'Reversed 24-bit RGBA ANSI background color code (10,20,30) should add matching former foreground color inline style.');
+			},
+			(reversedBack) => {
+				assert.strictEqual(1, reversedBack.classList.length, 'Reversed Back - background ANSI color codes should only add a single class.');
+				assert(reversedBack.classList.contains('code-background-colored') === false, 'AFTER Reversed Back - Background ANSI color should NOT BE SET.');
+				assert(reversedBack.classList.contains('code-foreground-colored'), 'Reversed Back -  Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(reversedBack, 'foreground', new RGBA(10, 20, 30), 'Reversed Back -  24-bit RGBA ANSI color code (10,20,30) should add matching color inline style.');
+			},
+		], 3);
+
+		// Reverse video reverses Foreground/Background colors WITH ONLY background color SET
+		assertMultipleSequenceElements('\x1b[48;2;167;168;169mbg167,168,169\x1b[7m8ReverseVideo\x1b[27mReverseOff', [
+			(bg167_168_169) => {
+				assert.strictEqual(1, bg167_168_169.classList.length, 'Background ANSI color code should add one class.');
+				assert(bg167_168_169.classList.contains('code-background-colored'), 'Background ANSI color codes should add custom foreground color class.');
+				assertInlineColor(bg167_168_169, 'background', new RGBA(167, 168, 169), '24-bit RGBA ANSI color code (167, 168, 169) should add matching background color inline style.');
+			},
+			(reverseVideo) => {
+				assert.strictEqual(1, reverseVideo.classList.length, 'After ReverseVideo Foreground ANSI color codes should only add a single class.');
+				assert(reverseVideo.classList.contains('code-foreground-colored'), 'After ReverseVideo Foreground ANSI color codes should add custom background color class.');
+				assert(reverseVideo.classList.contains('code-background-colored') === false, 'After Reverse with NO foreground color the background ANSI color codes should BE SET.');
+				assertInlineColor(reverseVideo, 'foreground', new RGBA(167, 168, 169), 'Reversed 24-bit RGBA ANSI background color code (10,20,30) should add matching former background color inline style.');
+			},
+			(reversedBack) => {
+				assert.strictEqual(1, reversedBack.classList.length, 'Reversed Back - background ANSI color codes should only add a single class.');
+				assert(reversedBack.classList.contains('code-foreground-colored') === false, 'AFTER Reversed Back - Foreground ANSI color should NOT BE SET.');
+				assert(reversedBack.classList.contains('code-background-colored'), 'Reversed Back -  Background ANSI color codes should add custom background color class.');
+				assertInlineColor(reversedBack, 'background', new RGBA(167, 168, 169), 'Reversed Back -  24-bit RGBA ANSI color code (10,20,30) should add matching background color inline style.');
+			},
+		], 3);
+
+		// Underline color Different types of color codes still cancel each other
+		assertMultipleSequenceElements('\x1b[58;2;101;102;103m24bitUnderline101,102,103\x1b[58;5;3m8bitsimpleUnderline\x1b[58;2;104;105;106m24bitUnderline104,105,106\x1b[58;5;101m8bitadvanced\x1b[58;2;200;200;200munderline200,200,200\x1b[59mUnderlineColorResetToDefault', [
+			(adv24Bit) => {
+				assert.strictEqual(1, adv24Bit.classList.length, 'Underline ANSI color codes should only add a single class (1).');
+				assert(adv24Bit.classList.contains('code-underline-colored'), 'Underline ANSI color codes should add custom underline color class.');
+				assertInlineColor(adv24Bit, 'underline', new RGBA(101, 102, 103), '24-bit RGBA ANSI color code (101,102,103) should add matching color inline style.');
+			},
+			(adv8BitSimple) => {
+				assert.strictEqual(1, adv8BitSimple.classList.length, 'Multiple underline ANSI color codes should only add a single class (2).');
+				assert(adv8BitSimple.classList.contains('code-underline-colored'), 'Underline ANSI color codes should add custom underline color class.');
+				// changed to simple theme color, don't know exactly what it should be, but it should NO LONGER BE 101,102,103
+				assertInlineColor(adv8BitSimple, 'underline', new RGBA(101, 102, 103), 'Change to theme color SHOULD NOT STILL BE 24-bit RGBA ANSI color code (101,102,103) should add matching color inline style.', false);
+			},
+			(adv24BitAgain) => {
+				assert.strictEqual(1, adv24BitAgain.classList.length, 'Multiple underline ANSI color codes should only add a single class (3).');
+				assert(adv24BitAgain.classList.contains('code-underline-colored'), 'Underline ANSI color codes should add custom underline color class.');
+				assertInlineColor(adv24BitAgain, 'underline', new RGBA(104, 105, 106), '24-bit RGBA ANSI color code (100,100,100) should add matching color inline style.');
+			},
+			(adv8BitAdvanced) => {
+				assert.strictEqual(1, adv8BitAdvanced.classList.length, 'Multiple underline ANSI color codes should only add a single class (4).');
+				assert(adv8BitAdvanced.classList.contains('code-underline-colored'), 'Underline ANSI color codes should add custom underline color class.');
+				// changed to 8bit advanced color, don't know exactly what it should be, but it should NO LONGER BE 104,105,106
+				assertInlineColor(adv8BitAdvanced, 'underline', new RGBA(104, 105, 106), 'Change to theme color SHOULD NOT BE 24-bit RGBA ANSI color code (104,105,106) should add matching color inline style.', false);
+			},
+			(adv24BitUnderlin200) => {
+				assert.strictEqual(1, adv24BitUnderlin200.classList.length, 'Multiple underline ANSI color codes should only add a single class 4.');
+				assert(adv24BitUnderlin200.classList.contains('code-underline-colored'), 'Underline ANSI color codes should add custom underline color class.');
+				assertInlineColor(adv24BitUnderlin200, 'underline', new RGBA(200, 200, 200), 'after change underline color SHOULD BE 24-bit RGBA ANSI color code (200,200,200) should add matching color inline style.');
+			},
+			(underlineColorResetToDefault) => {
+				assert.strictEqual(0, underlineColorResetToDefault.classList.length, 'After Underline Color reset to default NO underline color class should be set.');
+				assertInlineColor(underlineColorResetToDefault, 'underline', undefined, 'after RESET TO DEFAULT underline color SHOULD NOT BE SET (no color inline style.)');
+			},
+		], 6);
+
 		// Different types of color codes still cancel each other
-		assertMultipleSequenceElements('\x1b[34msimple\x1b[38;2;100;100;100m24bit\x1b[38;5;3m8bitsimple\x1b[38;5;101m8bitadvanced', [
+		assertMultipleSequenceElements('\x1b[34msimple\x1b[38;2;101;102;103m24bit\x1b[38;5;3m8bitsimple\x1b[38;2;104;105;106m24bitAgain\x1b[38;5;101m8bitadvanced', [
 			(simple) => {
 				assert.strictEqual(1, simple.classList.length, 'Foreground ANSI color code should add one class.');
 				assert(simple.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
@@ -380,18 +919,26 @@ suite('Debug - ANSI Handling', () => {
 			(adv24Bit) => {
 				assert.strictEqual(1, adv24Bit.classList.length, 'Multiple foreground ANSI color codes should only add a single class.');
 				assert(adv24Bit.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
-				assertInlineColor(adv24Bit, 'foreground', new RGBA(100, 100, 100), '24-bit RGBA ANSI color code (100,100,100) should add matching color inline style.');
+				assertInlineColor(adv24Bit, 'foreground', new RGBA(101, 102, 103), '24-bit RGBA ANSI color code (101,102,103) should add matching color inline style.');
 			},
 			(adv8BitSimple) => {
 				assert.strictEqual(1, adv8BitSimple.classList.length, 'Multiple foreground ANSI color codes should only add a single class.');
 				assert(adv8BitSimple.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
-				// Won't assert color because it's theme based
+				//color is theme based, so we can't check what it should be but we know it should NOT BE 101,102,103 anymore
+				assertInlineColor(adv8BitSimple, 'foreground', new RGBA(101, 102, 103), 'SHOULD NOT LONGER BE 24-bit RGBA ANSI color code (101,102,103) after simple color change.', false);
+			},
+			(adv24BitAgain) => {
+				assert.strictEqual(1, adv24BitAgain.classList.length, 'Multiple foreground ANSI color codes should only add a single class.');
+				assert(adv24BitAgain.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
+				assertInlineColor(adv24BitAgain, 'foreground', new RGBA(104, 105, 106), '24-bit RGBA ANSI color code (104,105,106) should add matching color inline style.');
 			},
 			(adv8BitAdvanced) => {
 				assert.strictEqual(1, adv8BitAdvanced.classList.length, 'Multiple foreground ANSI color codes should only add a single class.');
 				assert(adv8BitAdvanced.classList.contains('code-foreground-colored'), 'Foreground ANSI color codes should add custom foreground color class.');
+				// color should NO LONGER BE 104,105,106
+				assertInlineColor(adv8BitAdvanced, 'foreground', new RGBA(104, 105, 106), 'SHOULD NOT LONGER BE 24-bit RGBA ANSI color code (104,105,106) after advanced color change.', false);
 			}
-		], 4);
+		], 5);
 
 	});