diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 4f6726cd174..dc4798fc896 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -204,8 +204,8 @@ export const activate: ActivationFunction = (ctx) => { previewNode.classList.add('emptyMarkdownCell'); } else { previewNode.classList.remove('emptyMarkdownCell'); - - const unsanitizedRenderedMarkdown = markdownIt.render(text); + const markdownText = outputInfo.mime.startsWith('text/x-') ? `\`\`\`${outputInfo.mime.substr(7)}\n${text}\n\`\`\`` : text; + const unsanitizedRenderedMarkdown = markdownIt.render(markdownText); previewNode.innerHTML = (ctx.workspace.isTrusted ? unsanitizedRenderedMarkdown : DOMPurify.sanitize(unsanitizedRenderedMarkdown, sanitizerOptions)) as string; diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index d5f6385b3c0..8fdadcc3082 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -47,7 +47,79 @@ "entrypoint": "./notebook-out/index.js", "mimeTypes": [ "text/markdown", - "text/latex" + "text/latex", + "text/x-css", + "text/x-html", + "text/x-json", + "text/x-typescript", + "text/x-abap", + "text/x-apex", + "text/x-azcli", + "text/x-bat", + "text/x-cameligo", + "text/x-clojure", + "text/x-coffee", + "text/x-cpp", + "text/x-csharp", + "text/x-csp", + "text/x-css", + "text/x-dart", + "text/x-dockerfile", + "text/x-ecl", + "text/x-fsharp", + "text/x-go", + "text/x-graphql", + "text/x-handlebars", + "text/x-hcl", + "text/x-html", + "text/x-ini", + "text/x-java", + "text/x-javascript", + "text/x-julia", + "text/x-kotlin", + "text/x-less", + "text/x-lexon", + "text/x-lua", + "text/x-m3", + "text/x-markdown", + "text/x-mips", + "text/x-msdax", + "text/x-mysql", + "text/x-objective-c/objective", + "text/x-pascal", + "text/x-pascaligo", + "text/x-perl", + "text/x-pgsql", + "text/x-php", + "text/x-postiats", + "text/x-powerquery", + "text/x-powershell", + "text/x-pug", + "text/x-python", + "text/x-r", + "text/x-razor", + "text/x-redis", + "text/x-redshift", + "text/x-restructuredtext", + "text/x-ruby", + "text/x-rust", + "text/x-sb", + "text/x-scala", + "text/x-scheme", + "text/x-scss", + "text/x-shell", + "text/x-solidity", + "text/x-sophia", + "text/x-sql", + "text/x-st", + "text/x-swift", + "text/x-systemverilog", + "text/x-tcl", + "text/x-twig", + "text/x-typescript", + "text/x-vb", + "text/x-xml", + "text/x-yaml" ] } ], diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index c652e2f44f7..d2f6a9f32c6 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -816,6 +816,28 @@ var requirejs = (function() { cell.renderedHtml = data.html; } + for (const { id, value, lang } of data.codeBlocks) { + // The language id may be a language aliases (e.g.js instead of javascript) + const languageId = this.languageService.getLanguageIdByLanguageName(lang); + if (!languageId) { + continue; + } + + tokenizeToString(this.languageService, value, languageId).then((html) => { + if (this._disposed) { + return; + } + this._sendMessageToWebview({ + type: 'tokenizedCodeBlock', + html, + codeBlockId: id + }); + }); + } + break; + } + case 'renderedCellOutput': + { for (const { id, value, lang } of data.codeBlocks) { // The language id may be a language aliases (e.g.js instead of javascript) const languageId = this.languageService.getLanguageIdByLanguageName(lang); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 7b6b0faf039..0df26284cba 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -150,6 +150,15 @@ export interface IRenderedMarkupMessage extends BaseToWebviewMessage { }>; } +export interface IRenderedCellOutputMessage extends BaseToWebviewMessage { + readonly type: 'renderedCellOutput'; + readonly codeBlocks: ReadonlyArray<{ + readonly id: string; + readonly value: string; + readonly lang: string; + }>; +} + export interface IClearMessage { readonly type: 'clear'; } @@ -418,6 +427,7 @@ export type FromWebviewMessage = WebviewInitialized | ICellDragEndMessage | IInitializedMarkupMessage | IRenderedMarkupMessage | + IRenderedCellOutputMessage | IDidFindMessage | IDidFindHighlightMessage; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index c8c25c78cc8..25199afd549 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1146,6 +1146,7 @@ async function webviewPreloads(ctx: PreloadContext) { case 'tokenizedCodeBlock': { const { codeBlockId, html } = event.data; MarkupCell.highlightCodeBlock(codeBlockId, html); + OutputElement.highlightCodeBlock(codeBlockId, html); break; } case 'tokenizedStylesChanged': { @@ -1925,6 +1926,19 @@ async function webviewPreloads(ctx: PreloadContext) { } class OutputElement { + private static pendingCodeBlocksToHighlight = new Map(); + + public static highlightCodeBlock(id: string, html: string) { + const el = OutputElement.pendingCodeBlocksToHighlight.get(id); + if (!el) { + return; + } + const trustedHtml = ttPolicy?.createHTML(html) ?? html; + el.innerHTML = trustedHtml as string; + if (tokenizationStyleElement) { + el.insertAdjacentElement('beforebegin', tokenizationStyleElement.cloneNode(true) as HTMLElement); + } + } public readonly element: HTMLElement; @@ -1987,6 +2001,24 @@ async function webviewPreloads(ctx: PreloadContext) { init: true, }); } + + const codeBlocks: Array<{ value: string; lang: string; id: string }> = []; + let i = 0; + const root = this.element.shadowRoot ?? this.element; + for (const el of root.querySelectorAll('.vscode-code-block')) { + const lang = el.getAttribute('data-vscode-code-block-lang'); + if (el.textContent && lang) { + const id = `${Date.now()}-${i++}`; + codeBlocks.push({ value: el.textContent, lang: lang, id }); + OutputElement.pendingCodeBlocksToHighlight.set(id, el as HTMLElement); + } + } + + if (codeBlocks.length > 0) { + postNotebookMessage('renderedCellOutput', { + codeBlocks + }); + } } public rerender() {