123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /*---------------------------------------------------------------------------------------------
- * 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 /* Text */) {
- child = document.createTextNode(treeNode.content || '');
- }
- else if (treeNode.type === 3 /* Bold */) {
- child = document.createElement('b');
- }
- else if (treeNode.type === 4 /* Italics */) {
- child = document.createElement('i');
- }
- else if (treeNode.type === 7 /* Code */ && renderCodeSegments) {
- child = document.createElement('code');
- }
- else if (treeNode.type === 5 /* Action */ && actionHandler) {
- const a = document.createElement('a');
- a.href = '#';
- actionHandler.disposables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {
- actionHandler.callback(String(treeNode.index), event);
- }));
- child = a;
- }
- else if (treeNode.type === 8 /* NewLine */) {
- child = document.createElement('br');
- }
- else if (treeNode.type === 1 /* 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 /* 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 /* 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 /* Text */) {
- current = stack.pop();
- }
- const type = formatTagType(next, parseCodeSegments);
- if (current.type === type || (current.type === 5 /* Action */ && type === 6 /* ActionClose */)) {
- current = stack.pop();
- }
- else {
- const newCurrent = {
- type: type,
- children: []
- };
- if (type === 5 /* Action */) {
- newCurrent.index = actionViewItemIndex;
- actionViewItemIndex++;
- }
- current.children.push(newCurrent);
- stack.push(current);
- current = newCurrent;
- }
- }
- else if (next === '\n') {
- if (current.type === 2 /* Text */) {
- current = stack.pop();
- }
- current.children.push({
- type: 8 /* NewLine */
- });
- }
- else {
- if (current.type !== 2 /* Text */) {
- const textCurrent = {
- type: 2 /* Text */,
- content: next
- };
- current.children.push(textCurrent);
- stack.push(current);
- current = textCurrent;
- }
- else {
- current.content += next;
- }
- }
- }
- if (current.type === 2 /* Text */) {
- current = stack.pop();
- }
- if (stack.length) {
- // incorrectly formatted string literal
- }
- return root;
- }
- function isFormatTag(char, supportCodeSegments) {
- return formatTagType(char, supportCodeSegments) !== 0 /* Invalid */;
- }
- function formatTagType(char, supportCodeSegments) {
- switch (char) {
- case '*':
- return 3 /* Bold */;
- case '_':
- return 4 /* Italics */;
- case '[':
- return 5 /* Action */;
- case ']':
- return 6 /* ActionClose */;
- case '`':
- return supportCodeSegments ? 7 /* Code */ : 0 /* Invalid */;
- default:
- return 0 /* Invalid */;
- }
- }
|