neocities/public/js/monaco/esm/vs/base/browser/formattedTextRenderer.js

167 lines
5.8 KiB
JavaScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from './dom.js';
export function renderText(text, options = {}) {
const element = createElement(options);
element.textContent = text;
return element;
}
export function renderFormattedText(formattedText, options = {}) {
const element = createElement(options);
_renderFormattedText(element, parseFormattedText(formattedText, !!options.renderCodeSegments), options.actionHandler, options.renderCodeSegments);
return element;
}
export function createElement(options) {
const tagName = options.inline ? 'span' : 'div';
const element = document.createElement(tagName);
if (options.className) {
element.className = options.className;
}
return element;
}
class StringStream {
constructor(source) {
this.source = source;
this.index = 0;
}
eos() {
return this.index >= this.source.length;
}
next() {
const next = this.peek();
this.advance();
return next;
}
peek() {
return this.source[this.index];
}
advance() {
this.index++;
}
}
function _renderFormattedText(element, treeNode, actionHandler, renderCodeSegments) {
let child;
if (treeNode.type === 2 /* FormatType.Text */) {
child = document.createTextNode(treeNode.content || '');
}
else if (treeNode.type === 3 /* FormatType.Bold */) {
child = document.createElement('b');
}
else if (treeNode.type === 4 /* FormatType.Italics */) {
child = document.createElement('i');
}
else if (treeNode.type === 7 /* FormatType.Code */ && renderCodeSegments) {
child = document.createElement('code');
}
else if (treeNode.type === 5 /* FormatType.Action */ && actionHandler) {
const a = document.createElement('a');
actionHandler.disposables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {
actionHandler.callback(String(treeNode.index), event);
}));
child = a;
}
else if (treeNode.type === 8 /* FormatType.NewLine */) {
child = document.createElement('br');
}
else if (treeNode.type === 1 /* FormatType.Root */) {
child = element;
}
if (child && element !== child) {
element.appendChild(child);
}
if (child && Array.isArray(treeNode.children)) {
treeNode.children.forEach((nodeChild) => {
_renderFormattedText(child, nodeChild, actionHandler, renderCodeSegments);
});
}
}
function parseFormattedText(content, parseCodeSegments) {
const root = {
type: 1 /* FormatType.Root */,
children: []
};
let actionViewItemIndex = 0;
let current = root;
const stack = [];
const stream = new StringStream(content);
while (!stream.eos()) {
let next = stream.next();
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek(), parseCodeSegments) !== 0 /* FormatType.Invalid */);
if (isEscapedFormatType) {
next = stream.next(); // unread the backslash if it escapes a format tag type
}
if (!isEscapedFormatType && isFormatTag(next, parseCodeSegments) && next === stream.peek()) {
stream.advance();
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
const type = formatTagType(next, parseCodeSegments);
if (current.type === type || (current.type === 5 /* FormatType.Action */ && type === 6 /* FormatType.ActionClose */)) {
current = stack.pop();
}
else {
const newCurrent = {
type: type,
children: []
};
if (type === 5 /* FormatType.Action */) {
newCurrent.index = actionViewItemIndex;
actionViewItemIndex++;
}
current.children.push(newCurrent);
stack.push(current);
current = newCurrent;
}
}
else if (next === '\n') {
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
current.children.push({
type: 8 /* FormatType.NewLine */
});
}
else {
if (current.type !== 2 /* FormatType.Text */) {
const textCurrent = {
type: 2 /* FormatType.Text */,
content: next
};
current.children.push(textCurrent);
stack.push(current);
current = textCurrent;
}
else {
current.content += next;
}
}
}
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
if (stack.length) {
// incorrectly formatted string literal
}
return root;
}
function isFormatTag(char, supportCodeSegments) {
return formatTagType(char, supportCodeSegments) !== 0 /* FormatType.Invalid */;
}
function formatTagType(char, supportCodeSegments) {
switch (char) {
case '*':
return 3 /* FormatType.Bold */;
case '_':
return 4 /* FormatType.Italics */;
case '[':
return 5 /* FormatType.Action */;
case ']':
return 6 /* FormatType.ActionClose */;
case '`':
return supportCodeSegments ? 7 /* FormatType.Code */ : 0 /* FormatType.Invalid */;
default:
return 0 /* FormatType.Invalid */;
}
}