Files
azuredatastudio/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts
Anthony Dresser 87765e8673 Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
2019-03-19 17:44:35 -07:00

134 lines
4.2 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
/**
* @param text The content to stylize.
* @returns An {@link HTMLSpanElement} that contains the potentially stylized text.
*/
export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTMLSpanElement {
const root: HTMLSpanElement = document.createElement('span');
const textLength: number = text.length;
let styleNames: string[] = [];
let currentPos: number = 0;
let buffer: string = '';
while (currentPos < textLength) {
let sequenceFound: boolean = false;
// Potentially an ANSI escape sequence.
// See http://ascii-table.com/ansi-escape-sequences.php & https://en.wikipedia.org/wiki/ANSI_escape_code
if (text.charCodeAt(currentPos) === 27 && text.charAt(currentPos + 1) === '[') {
const startPos: number = currentPos;
currentPos += 2; // Ignore 'Esc[' as it's in every sequence.
let ansiSequence: string = '';
while (currentPos < textLength) {
const char: string = text.charAt(currentPos);
ansiSequence += char;
currentPos++;
// Look for a known sequence terminating character.
if (char.match(/^[ABCDHIJKfhmpsu]$/)) {
sequenceFound = true;
break;
}
}
if (sequenceFound) {
// Flush buffer with previous styles.
appendStylizedStringToContainer(root, buffer, styleNames, linkDetector);
buffer = '';
/*
* 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(/^(?:[349][0-7]|10[0-7]|[013]|4|[34]9)(?:;(?:[349][0-7]|10[0-7]|[013]|4|[34]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.
for (let code of styleCodes) {
if (code === 0) {
styleNames = [];
} else if (code === 1) {
styleNames.push('code-bold');
} else if (code === 3) {
styleNames.push('code-italic');
} else if (code === 4) {
styleNames.push('code-underline');
} else if (code === 39 || (code >= 30 && code <= 37) || (code >= 90 && code <= 97)) {
// Remove all previous foreground colour codes
styleNames = styleNames.filter(style => !style.match(/^code-foreground-\d+$/));
if (code !== 39) {
styleNames.push('code-foreground-' + code);
}
} else if (code === 49 || (code >= 40 && code <= 47) || (code >= 100 && code <= 107)) {
// Remove all previous background colour codes
styleNames = styleNames.filter(style => !style.match(/^code-background-\d+$/));
if (code !== 49) {
styleNames.push('code-background-' + code);
}
}
}
} else {
// Unsupported sequence so simply hide it.
}
} else {
currentPos = startPos;
}
}
if (sequenceFound === false) {
buffer += text.charAt(currentPos);
currentPos++;
}
}
// Flush remaining text buffer if not empty.
if (buffer) {
appendStylizedStringToContainer(root, buffer, styleNames, linkDetector);
}
return root;
}
/**
* @param root The {@link HTMLElement} to append the content to.
* @param stringContent The text content to be appended.
* @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}.
*/
export function appendStylizedStringToContainer(root: HTMLElement, stringContent: string, cssClasses: string[], linkDetector: LinkDetector): void {
if (!root || !stringContent) {
return;
}
const container = linkDetector.handleLinks(stringContent);
container.className = cssClasses.join(' ');
root.appendChild(container);
}