diff --git a/extensions/notebook-renderers/src/ansi.ts b/extensions/notebook-renderers/src/ansi.ts index d09e7b73edb..48d280b18b4 100644 --- a/extensions/notebook-renderers/src/ansi.ts +++ b/extensions/notebook-renderers/src/ansi.ts @@ -5,11 +5,10 @@ import { RGBA, Color } from './color'; import { ansiColorIdentifiers } from './colorMap'; -import { linkify } from './linkify'; +import { LinkOptions, linkify } from './linkify'; -export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElement { - const workspaceFolder = undefined; +export function handleANSIOutput(text: string, linkOptions: LinkOptions): HTMLSpanElement { const root: HTMLSpanElement = document.createElement('span'); const textLength: number = text.length; @@ -52,7 +51,7 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem if (sequenceFound) { // Flush buffer with previous styles. - appendStylizedStringToContainer(root, buffer, trustHtml, styleNames, workspaceFolder, customFgColor, customBgColor, customUnderlineColor); + appendStylizedStringToContainer(root, buffer, linkOptions, styleNames, customFgColor, customBgColor, customUnderlineColor); buffer = ''; @@ -98,7 +97,7 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem // Flush remaining text buffer if not empty. if (buffer) { - appendStylizedStringToContainer(root, buffer, trustHtml, styleNames, workspaceFolder, customFgColor, customBgColor, customUnderlineColor); + appendStylizedStringToContainer(root, buffer, linkOptions, styleNames, customFgColor, customBgColor, customUnderlineColor); } return root; @@ -382,9 +381,8 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem function appendStylizedStringToContainer( root: HTMLElement, stringContent: string, - trustHtml: boolean, + linkOptions: LinkOptions, cssClasses: string[], - workspaceFolder: string | undefined, customTextColor?: RGBA | string, customBackgroundColor?: RGBA | string, customUnderlineColor?: RGBA | string @@ -397,7 +395,7 @@ function appendStylizedStringToContainer( if (container.childElementCount === 0) { // plain text - container = linkify(stringContent, true, workspaceFolder, trustHtml); + container = linkify(stringContent, linkOptions, true); } container.className = cssClasses.join(' '); diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index ba57767b7fc..ff79bd0e22e 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -176,7 +176,9 @@ function renderError( const stackTrace = formatStackTrace(err.stack); const outputScrolling = scrollingEnabled(outputInfo, ctx.settings); - const content = createOutputContent(outputInfo.id, stackTrace ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml }); + const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml, linkifyFilePaths: ctx.settings.linkifyFilePaths }; + + const content = createOutputContent(outputInfo.id, stackTrace ?? '', outputOptions); const contentParent = document.createElement('div'); contentParent.classList.toggle('word-wrap', ctx.settings.outputWordWrap); disposableStore.push(ctx.onDidChangeSettings(e => { @@ -279,7 +281,7 @@ function scrollingEnabled(output: OutputItem, options: RenderOptions) { function renderStream(outputInfo: OutputWithAppend, outputElement: HTMLElement, error: boolean, ctx: IRichRenderContext): IDisposable { const disposableStore = createDisposableStore(); const outputScrolling = scrollingEnabled(outputInfo, ctx.settings); - const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, error }; + const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, error, linkifyFilePaths: ctx.settings.linkifyFilePaths }; outputElement.classList.add('output-stream'); @@ -330,7 +332,8 @@ function renderText(outputInfo: OutputItem, outputElement: HTMLElement, ctx: IRi const text = outputInfo.text(); const outputScrolling = scrollingEnabled(outputInfo, ctx.settings); - const content = createOutputContent(outputInfo.id, text, { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false }); + const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, linkifyFilePaths: ctx.settings.linkifyFilePaths }; + const content = createOutputContent(outputInfo.id, text, outputOptions); content.classList.add('output-plaintext'); if (ctx.settings.outputWordWrap) { content.classList.add('word-wrap'); diff --git a/extensions/notebook-renderers/src/linkify.ts b/extensions/notebook-renderers/src/linkify.ts index 49fdc4edf8c..c625c5fdba5 100644 --- a/extensions/notebook-renderers/src/linkify.ts +++ b/extensions/notebook-renderers/src/linkify.ts @@ -26,6 +26,11 @@ type LinkPart = { captures: string[]; }; +export type LinkOptions = { + trustHtml?: boolean; + linkifyFilePaths: boolean; +}; + export class LinkDetector { // used by unit tests @@ -51,7 +56,8 @@ export class LinkDetector { * When splitLines is true, each line of the text, even if it contains no links, is wrapped in a * and added as a child of the returned . */ - linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml?: boolean): HTMLElement { + linkify(text: string, options: LinkOptions, splitLines?: boolean): HTMLElement { + console.log('linkifyiiiiiing', JSON.stringify(options)); if (splitLines) { const lines = text.split('\n'); for (let i = 0; i < lines.length - 1; i++) { @@ -61,7 +67,7 @@ export class LinkDetector { // Remove the last element ('') that split added. lines.pop(); } - const elements = lines.map(line => this.linkify(line, false, workspaceFolder, trustHtml)); + const elements = lines.map(line => this.linkify(line, options, false)); if (elements.length === 1) { // Do not wrap single line with extra span. return elements[0]; @@ -72,8 +78,9 @@ export class LinkDetector { } const container = document.createElement('span'); - for (const part of this.detectLinks(text)) { + for (const part of this.detectLinks(text, !!options.trustHtml, options.linkifyFilePaths)) { try { + let span: HTMLSpanElement | null = null; switch (part.kind) { case 'text': container.appendChild(document.createTextNode(part.value)); @@ -83,13 +90,9 @@ export class LinkDetector { container.appendChild(this.createWebLink(part.value)); break; case 'html': - if (this.shouldGenerateHtml(!!trustHtml)) { - const span = document.createElement('span'); - span.innerHTML = this.createHtml(part.value)!; - container.appendChild(span); - } else { - container.appendChild(document.createTextNode(part.value)); - } + span = document.createElement('span'); + span.innerHTML = this.createHtml(part.value)!; + container.appendChild(span); break; } } catch (e) { @@ -149,15 +152,27 @@ export class LinkDetector { return link; } - private detectLinks(text: string): LinkPart[] { + private detectLinks(text: string, trustHtml: boolean, detectFilepaths: boolean): LinkPart[] { if (text.length > MAX_LENGTH) { return [{ kind: 'text', value: text, captures: [] }]; } - const regexes: RegExp[] = [HTML_LINK_REGEX, WEB_LINK_REGEX, PATH_LINK_REGEX]; - const kinds: LinkKind[] = ['html', 'web', 'path']; + const regexes: RegExp[] = []; + const kinds: LinkKind[] = []; const result: LinkPart[] = []; + if (this.shouldGenerateHtml(trustHtml)) { + regexes.push(HTML_LINK_REGEX); + kinds.push('html'); + } + regexes.push(WEB_LINK_REGEX); + kinds.push('web'); + if (detectFilepaths) { + regexes.push(PATH_LINK_REGEX); + kinds.push('path'); + } + + const splitOne = (text: string, regexIndex: number) => { if (regexIndex >= regexes.length) { result.push({ value: text, kind: 'text', captures: [] }); @@ -192,6 +207,6 @@ export class LinkDetector { } const linkDetector = new LinkDetector(); -export function linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml = false) { - return linkDetector.linkify(text, splitLines, workspaceFolder, trustHtml); +export function linkify(text: string, linkOptions: LinkOptions, splitLines?: boolean) { + return linkDetector.linkify(text, linkOptions, splitLines); } diff --git a/extensions/notebook-renderers/src/rendererTypes.ts b/extensions/notebook-renderers/src/rendererTypes.ts index ded12bdcacc..e1fc869a301 100644 --- a/extensions/notebook-renderers/src/rendererTypes.ts +++ b/extensions/notebook-renderers/src/rendererTypes.ts @@ -32,6 +32,7 @@ export interface RenderOptions { readonly lineLimit: number; readonly outputScrolling: boolean; readonly outputWordWrap: boolean; + readonly linkifyFilePaths: boolean; } export type IRichRenderContext = RendererContext & { readonly settings: RenderOptions; readonly onDidChangeSettings: Event }; @@ -41,6 +42,7 @@ export type OutputElementOptions = { scrollable?: boolean; error?: boolean; trustHtml?: boolean; + linkifyFilePaths: boolean; }; export interface OutputWithAppend extends OutputItem { diff --git a/extensions/notebook-renderers/src/test/linkify.test.ts b/extensions/notebook-renderers/src/test/linkify.test.ts index 7ee5487a84b..cae8f569423 100644 --- a/extensions/notebook-renderers/src/test/linkify.test.ts +++ b/extensions/notebook-renderers/src/test/linkify.test.ts @@ -15,27 +15,32 @@ suite('Notebook builtin output link detection', () => { LinkDetector.injectedHtmlCreator = (value: string) => value; test('no links', () => { - const htmlWithLinks = linkify('hello', true, undefined, true); + const htmlWithLinks = linkify('hello', { linkifyFilePaths: true, trustHtml: true }, true); assert.equal(htmlWithLinks.innerHTML, 'hello'); }); test('web link detection', () => { - const htmlWithLinks = linkify('something www.example.com something', true, undefined, true); + const htmlWithLinks = linkify('something www.example.com something', { linkifyFilePaths: true, trustHtml: true }, true); + const htmlWithLinks2 = linkify('something www.example.com something', { linkifyFilePaths: false, trustHtml: false }, true); assert.equal(htmlWithLinks.innerHTML, 'something www.example.com something'); assert.equal(htmlWithLinks.textContent, 'something www.example.com something'); + assert.equal(htmlWithLinks2.innerHTML, 'something www.example.com something'); + assert.equal(htmlWithLinks2.textContent, 'something www.example.com something'); }); test('html link detection', () => { - const htmlWithLinks = linkify('something link something', true, undefined, true); + const htmlWithLinks = linkify('something link something', { linkifyFilePaths: true, trustHtml: true }, true); + const htmlWithLinks2 = linkify('something link something', { linkifyFilePaths: false, trustHtml: true }, true); assert.equal(htmlWithLinks.innerHTML, 'something link something'); assert.equal(htmlWithLinks.textContent, 'something link something'); + assert.equal(htmlWithLinks2.innerHTML, 'something link something'); + assert.equal(htmlWithLinks2.textContent, 'something link something'); }); test('html link without trust', () => { - const trustHtml = false; - const htmlWithLinks = linkify('something link something', true, undefined, trustHtml); + const htmlWithLinks = linkify('something link something', { linkifyFilePaths: true, trustHtml: false }, true); assert.equal(htmlWithLinks.innerHTML, 'something <a href="file.py">link</a> something'); assert.equal(htmlWithLinks.textContent, 'something link something'); diff --git a/extensions/notebook-renderers/src/test/notebookRenderer.test.ts b/extensions/notebook-renderers/src/test/notebookRenderer.test.ts index 8e33720d337..07ec9cdf9ea 100644 --- a/extensions/notebook-renderers/src/test/notebookRenderer.test.ts +++ b/extensions/notebook-renderers/src/test/notebookRenderer.test.ts @@ -273,6 +273,36 @@ suite('Notebook builtin output renderer', () => { assert.ok(inserted.innerHTML.indexOf('shouldBeTruncated') === -1, `Beginning content should be truncated`); }); + test(`Render filepath links in text output when enabled`, async () => { + LinkDetector.injectedHtmlCreator = (value: string) => value; + const context = createContext({ outputWordWrap: true, outputScrolling: true, linkifyFilePaths: true }); + const renderer = await activate(context); + assert.ok(renderer, 'Renderer not created'); + + const outputElement = new OutputHtml().getFirstOuputElement(); + const outputItem = createOutputItem('./dir/file.txt', stdoutMimeType); + await renderer!.renderOutputItem(outputItem, outputElement); + + const inserted = outputElement.firstChild as HTMLElement; + assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`); + assert.ok(outputElement.innerHTML.indexOf('') !== -1, `inner HTML:\n ${outputElement.innerHTML}`); + }); + + test(`No filepath links in text output when disabled`, async () => { + LinkDetector.injectedHtmlCreator = (value: string) => value; + const context = createContext({ outputWordWrap: true, outputScrolling: true, linkifyFilePaths: false }); + const renderer = await activate(context); + assert.ok(renderer, 'Renderer not created'); + + const outputElement = new OutputHtml().getFirstOuputElement(); + const outputItem = createOutputItem('./dir/file.txt', stdoutMimeType); + await renderer!.renderOutputItem(outputItem, outputElement); + + const inserted = outputElement.firstChild as HTMLElement; + assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`); + assert.ok(outputElement.innerHTML.indexOf('') === -1, `inner HTML:\n ${outputElement.innerHTML}`); + }); + test(`Render with wordwrap and scrolling for error output`, async () => { LinkDetector.injectedHtmlCreator = (value: string) => value; const context = createContext({ outputWordWrap: true, outputScrolling: true }); @@ -474,7 +504,6 @@ suite('Notebook builtin output renderer', () => { const inserted = outputElement.firstChild as HTMLElement; assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`); - //assert.ok(false, `TextContent:\n ${outputElement.textContent}`); assert.ok(outputElement.innerHTML.indexOf('class="code-background-colored"') === -1, `inner HTML:\n ${outputElement.innerHTML}`); }); diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index 5cf0e24eb96..b49dbb6ad8d 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { handleANSIOutput } from './ansi'; +import { LinkOptions } from './linkify'; import { OutputElementOptions, OutputWithAppend } from './rendererTypes'; export const scrollableClass = 'scrollable'; @@ -68,44 +69,44 @@ function generateNestedViewAllElement(outputId: string) { return container; } -function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, trustHtml: boolean) { +function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, linkOptions: LinkOptions) { const container = document.createElement('div'); const lineCount = buffer.length; if (lineCount <= linesLimit) { - const spanElement = handleANSIOutput(buffer.join('\n'), trustHtml); + const spanElement = handleANSIOutput(buffer.join('\n'), linkOptions); container.appendChild(spanElement); return container; } - container.appendChild(handleANSIOutput(buffer.slice(0, linesLimit - 5).join('\n'), trustHtml)); + container.appendChild(handleANSIOutput(buffer.slice(0, linesLimit - 5).join('\n'), linkOptions)); // truncated piece const elipses = document.createElement('div'); elipses.innerText = '...'; container.appendChild(elipses); - container.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'), trustHtml)); + container.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'), linkOptions)); container.appendChild(generateViewMoreElement(id)); return container; } -function scrollableArrayOfString(id: string, buffer: string[], trustHtml: boolean) { +function scrollableArrayOfString(id: string, buffer: string[], linkOptions: LinkOptions) { const element = document.createElement('div'); if (buffer.length > softScrollableLineLimit) { element.appendChild(generateNestedViewAllElement(id)); } - element.appendChild(handleANSIOutput(buffer.slice(-1 * softScrollableLineLimit).join('\n'), trustHtml)); + element.appendChild(handleANSIOutput(buffer.slice(-1 * softScrollableLineLimit).join('\n'), linkOptions)); return element; } const outputLengths: Record = {}; -function appendScrollableOutput(element: HTMLElement, id: string, appended: string, trustHtml: boolean) { +function appendScrollableOutput(element: HTMLElement, id: string, appended: string, linkOptions: LinkOptions) { if (!outputLengths[id]) { outputLengths[id] = 0; } @@ -117,22 +118,23 @@ function appendScrollableOutput(element: HTMLElement, id: string, appended: stri return false; } else { - element.appendChild(handleANSIOutput(buffer.join('\n'), trustHtml)); + element.appendChild(handleANSIOutput(buffer.join('\n'), linkOptions)); outputLengths[id] = appendedLength; } return true; } export function createOutputContent(id: string, outputText: string, options: OutputElementOptions): HTMLElement { - const { linesLimit, error, scrollable, trustHtml } = options; + const { linesLimit, error, scrollable, trustHtml, linkifyFilePaths } = options; + const linkOptions: LinkOptions = { linkifyFilePaths, trustHtml }; const buffer = outputText.split(/\r\n|\r|\n/g); outputLengths[id] = outputLengths[id] = Math.min(buffer.length, softScrollableLineLimit); let outputElement: HTMLElement; if (scrollable) { - outputElement = scrollableArrayOfString(id, buffer, !!trustHtml); + outputElement = scrollableArrayOfString(id, buffer, linkOptions); } else { - outputElement = truncatedArrayOfString(id, buffer, linesLimit, !!trustHtml); + outputElement = truncatedArrayOfString(id, buffer, linesLimit, linkOptions); } outputElement.setAttribute('output-item-id', id); @@ -145,9 +147,10 @@ export function createOutputContent(id: string, outputText: string, options: Out export function appendOutput(outputInfo: OutputWithAppend, existingContent: HTMLElement, options: OutputElementOptions) { const appendedText = outputInfo.appendedText?.(); + const linkOptions = { linkifyFilePaths: options.linkifyFilePaths, trustHtml: options.trustHtml }; // appending output only supported for scrollable ouputs currently if (appendedText && options.scrollable) { - if (appendScrollableOutput(existingContent, outputInfo.id, appendedText, false)) { + if (appendScrollableOutput(existingContent, outputInfo.id, appendedText, linkOptions)) { return; } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 943d28abb05..b0c8c072e62 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -922,6 +922,12 @@ configurationRegistry.registerConfiguration({ tags: ['notebookLayout', 'notebookOutputLayout'], minimum: 1, }, + [NotebookSetting.LinkifyOutputFilePaths]: { + description: nls.localize('notebook.disableOutputFilePathLinks', "Control whether to disable filepath links in the output of notebook cells."), + type: 'boolean', + default: true, + tags: ['notebookOutputLayout'] + }, [NotebookSetting.markupFontSize]: { markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size in pixels of rendered markup in notebooks. When set to {0}, 120% of {1} is used.", '`0`', '`#editor.fontSize#`'), type: 'number', diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 745adff1205..424862aeca3 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -372,6 +372,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD || e.outputFontFamily || e.outputWordWrap || e.outputScrolling + || e.outputLinkifyFilePaths ) { this._styleElement?.remove(); this._createLayoutStyles(); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts b/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts index c8bbccd4702..9e4c743e3ef 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts @@ -50,6 +50,7 @@ export interface NotebookDisplayOptions { outputScrolling: boolean; outputWordWrap: boolean; outputLineLimit: number; + outputLinkifyFilePaths: boolean; fontSize: number; outputFontSize: number; outputFontFamily: string; @@ -106,6 +107,7 @@ export interface NotebookOptionsChangeEvent { readonly outputLineHeight?: boolean; readonly outputWordWrap?: boolean; readonly outputScrolling?: boolean; + readonly outputLinkifyFilePaths?: boolean; } const defaultConfigConstants = Object.freeze({ @@ -199,6 +201,7 @@ export class NotebookOptions extends Disposable { const outputLineHeight = this._computeOutputLineHeight(outputLineHeightSettingValue, outputFontSize); const outputWordWrap = this.configurationService.getValue(NotebookSetting.outputWordWrap); const outputLineLimit = this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30; + const linkifyFilePaths = this.configurationService.getValue(NotebookSetting.LinkifyOutputFilePaths) ?? true; this._layoutConfiguration = { ...(compactView ? compactConfigConstants : defaultConfigConstants), @@ -239,7 +242,8 @@ export class NotebookOptions extends Disposable { markdownFoldHintHeight: 22, outputScrolling: outputScrolling, outputWordWrap: outputWordWrap, - outputLineLimit: outputLineLimit + outputLineLimit: outputLineLimit, + outputLinkifyFilePaths: linkifyFilePaths }; this._register(this.configurationService.onDidChangeConfiguration(e => { @@ -355,6 +359,7 @@ export class NotebookOptions extends Disposable { const outputLineHeight = e.affectsConfiguration(NotebookSetting.outputLineHeight); const outputScrolling = e.affectsConfiguration(NotebookSetting.outputScrolling); const outputWordWrap = e.affectsConfiguration(NotebookSetting.outputWordWrap); + const outputLinkifyFilePaths = e.affectsConfiguration(NotebookSetting.LinkifyOutputFilePaths); if ( !cellStatusBarVisibility @@ -379,7 +384,8 @@ export class NotebookOptions extends Disposable { && !interactiveWindowCollapseCodeCells && !outputLineHeight && !outputScrolling - && !outputWordWrap) { + && !outputWordWrap + && !outputLinkifyFilePaths) { return; } @@ -478,6 +484,10 @@ export class NotebookOptions extends Disposable { configuration.outputScrolling = this.configurationService.getValue(NotebookSetting.outputScrolling); } + if (outputLinkifyFilePaths) { + configuration.outputLinkifyFilePaths = this.configurationService.getValue(NotebookSetting.LinkifyOutputFilePaths); + } + this._layoutConfiguration = Object.freeze(configuration); // trigger event @@ -504,7 +514,8 @@ export class NotebookOptions extends Disposable { interactiveWindowCollapseCodeCells, outputLineHeight, outputScrolling, - outputWordWrap + outputWordWrap, + outputLinkifyFilePaths: outputLinkifyFilePaths }); } @@ -713,6 +724,7 @@ export class NotebookOptions extends Disposable { outputScrolling: this._layoutConfiguration.outputScrolling, outputWordWrap: this._layoutConfiguration.outputWordWrap, outputLineLimit: this._layoutConfiguration.outputLineLimit, + outputLinkifyFilePaths: this._layoutConfiguration.outputLinkifyFilePaths, }; } @@ -734,6 +746,7 @@ export class NotebookOptions extends Disposable { outputScrolling: this._layoutConfiguration.outputScrolling, outputWordWrap: this._layoutConfiguration.outputWordWrap, outputLineLimit: this._layoutConfiguration.outputLineLimit, + outputLinkifyFilePaths: false }; } 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 83a3f715efd..6891a9ff4bf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -117,6 +117,7 @@ interface BacklayerWebviewOptions { readonly outputScrolling: boolean; readonly outputWordWrap: boolean; readonly outputLineLimit: number; + readonly outputLinkifyFilePaths: boolean; } @@ -245,7 +246,8 @@ export class BackLayerWebView extends Themable { renderOptions: { lineLimit: this.options.outputLineLimit, outputScrolling: this.options.outputScrolling, - outputWordWrap: this.options.outputWordWrap + outputWordWrap: this.options.outputWordWrap, + linkifyFilePaths: this.options.outputLinkifyFilePaths, } }); } @@ -283,7 +285,8 @@ export class BackLayerWebView extends Themable { const renderOptions = { lineLimit: this.options.outputLineLimit, outputScrolling: this.options.outputScrolling, - outputWordWrap: this.options.outputWordWrap + outputWordWrap: this.options.outputWordWrap, + linkifyFilePaths: this.options.outputLinkifyFilePaths }; const preloadScript = preloadsScriptStr( { 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 802a46145f8..6a0eb8e644b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -70,6 +70,7 @@ export interface RenderOptions { readonly lineLimit: number; readonly outputScrolling: boolean; readonly outputWordWrap: boolean; + readonly linkifyFilePaths: boolean; } interface PreloadContext { @@ -1696,6 +1697,7 @@ async function webviewPreloads(ctx: PreloadContext) { get lineLimit() { return currentRenderOptions.lineLimit; }, get outputScrolling() { return currentRenderOptions.outputScrolling; }, get outputWordWrap() { return currentRenderOptions.outputWordWrap; }, + get linkifyFilePaths() { return currentRenderOptions.linkifyFilePaths; }, }, get onDidChangeSettings() { return settingChange.event; } }; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 29b3da03f12..e076f6ebf7e 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -956,6 +956,7 @@ export const NotebookSetting = { outputScrollingDeprecated: 'notebook.experimental.outputScrolling', outputScrolling: 'notebook.output.scrolling', textOutputLineLimit: 'notebook.output.textLineLimit', + LinkifyOutputFilePaths: 'notebook.output.linkifyFilePaths', formatOnSave: 'notebook.formatOnSave.enabled', insertFinalNewline: 'notebook.insertFinalNewline', formatOnCellExecution: 'notebook.formatOnCellExecution',