From d7c8a6c272f58b80efbb2ffe082495ac6ebf957e Mon Sep 17 00:00:00 2001 From: aamunger Date: Fri, 11 Nov 2022 13:50:58 -0800 Subject: [PATCH 01/11] css change to scroll output --- extensions/notebook-renderers/src/index.ts | 13 ++++++++----- .../notebook-renderers/src/textHelper.ts | 18 ++++++++++++++++-- .../browser/view/renderers/backLayerWebView.ts | 4 +++- .../contrib/notebook/common/notebookCommon.ts | 3 ++- .../contrib/notebook/common/notebookOptions.ts | 7 ++++++- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 61098afe4f3..adfcf470bc3 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-notebook-renderer'; -import { truncatedArrayOfString } from './textHelper'; +import { insertOutput, truncatedArrayOfString } from './textHelper'; interface IDisposable { dispose(): void; @@ -153,7 +153,7 @@ function renderError(outputInfo: OutputItem, container: HTMLElement, ctx: Render container.classList.add('error'); } -function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boolean, ctx: RendererContext & { readonly settings: { readonly lineLimit: number } }): void { +function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boolean, ctx: RendererContext & { readonly settings: { readonly lineLimit: number; readonly outputScrolling: boolean } }): void { const outputContainer = container.parentElement; if (!outputContainer) { // should never happen @@ -170,7 +170,7 @@ function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boo const text = outputInfo.text(); const element = document.createElement('span'); - truncatedArrayOfString(outputInfo.id, [text], ctx.settings.lineLimit, element); + insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, true, element); outputElement.appendChild(element); return; } @@ -180,7 +180,7 @@ function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boo element.classList.add('output-stream'); const text = outputInfo.text(); - truncatedArrayOfString(outputInfo.id, [text], ctx.settings.lineLimit, element); + insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, true, element); while (container.firstChild) { container.removeChild(container.firstChild); } @@ -205,7 +205,7 @@ export const activate: ActivationFunction = (ctx) => { const htmlHooks = new Set(); const jsHooks = new Set(); - const latestContext = ctx as (RendererContext & { readonly settings: { readonly lineLimit: number } }); + const latestContext = ctx as (RendererContext & { readonly settings: { readonly lineLimit: number; readonly outputScrolling: boolean } }); const style = document.createElement('style'); style.textContent = ` @@ -225,6 +225,9 @@ export const activate: ActivationFunction = (ctx) => { } span.output-stream { display: inline-block; + width: 100%; + overflow-y: var(--notebook-output-overflow-y); + max-height: 500px; } .output-plaintext .code-bold, .output-stream .code-bold, diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index 36edb961f1f..6bd93b360dd 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -13,9 +13,9 @@ function generateViewMoreElement(outputId: string) { second.textContent = 'size limit'; second.href = `command:workbench.action.openSettings?%5B%22notebook.output.textLineLimit%22%5D`; const third = document.createElement('span'); - third.textContent = '. Open the full output data'; + third.textContent = '. Enable scrolling in the settings, or open the full output data '; const forth = document.createElement('a'); - forth.textContent = ' in a text editor'; + forth.textContent = 'in a text editor'; forth.href = `command:workbench.action.openLargeOutput?${outputId}`; container.appendChild(first); container.appendChild(second); @@ -49,3 +49,17 @@ export function truncatedArrayOfString(id: string, outputs: string[], linesLimit container.appendChild(div2); div2.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'))); } + +function scrollableArrayOfString(outputs: string[], container: HTMLElement) { + const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); + const spanElement = handleANSIOutput(buffer.slice(0, 5000).join('\n')); + container.appendChild(spanElement); +} + +export function insertOutput(id: string, outputs: string[], linesLimit: number, scrollable: boolean, container: HTMLElement) { + if (scrollable) { + scrollableArrayOfString(outputs, container); + } else { + truncatedArrayOfString(id, outputs, linesLimit, container); + } +} 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 23e427b6ed5..e3a8c13a9f0 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -97,6 +97,7 @@ interface BacklayerWebviewOptions { readonly outputFontFamily: string; readonly markupFontSize: number; readonly outputLineHeight: number; + readonly outputScrolling: boolean; } export class BackLayerWebView extends Themable { @@ -233,6 +234,7 @@ export class BackLayerWebView extends Themable { key: 'notebook.error.rendererNotFound', comment: ['$0 is a placeholder for the mime type'] }, "No renderer found for '$0' a"), + 'notebook-output-overflow-y': this.options.outputScrolling ? 'scroll' : 'visible', }; } @@ -241,7 +243,7 @@ export class BackLayerWebView extends Themable { const preloadsData = this.getStaticPreloadsData(); const preloadScript = preloadsScriptStr( this.options, - { dragAndDropEnabled: this.options.dragAndDropEnabled }, + { dragAndDropEnabled: this.options.dragAndDropEnabled }, // add other options renderersData, preloadsData, this.workspaceTrustManagementService.isWorkspaceTrusted(), diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 9cf0175219e..e27d9214e98 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -926,7 +926,8 @@ export const NotebookSetting = { outputLineHeight: 'notebook.outputLineHeight', outputFontSize: 'notebook.outputFontSize', outputFontFamily: 'notebook.outputFontFamily', - kernelPickerType: 'notebook.kernelPicker.type' + kernelPickerMRU: 'notebook.experimental.kernelPicker.mru', + outputScrolling: 'notebook.outputScrolling', } as const; export const enum CellStatusbarAlignment { diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 63661031729..19786b0af3f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -70,6 +70,7 @@ export interface NotebookLayoutConfiguration { editorOptionsCustomizations: any | undefined; focusIndicatorGap: number; interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells; + outputScrolling: boolean; } export interface NotebookOptionsChangeEvent { @@ -147,6 +148,7 @@ export class NotebookOptions extends Disposable { const editorOptionsCustomizations = this.configurationService.getValue(NotebookSetting.cellEditorOptionsCustomizations); const interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells); const outputLineHeight = this._computeOutputLineHeight(); + const outputScrolling = this.configurationService.getValue(NotebookSetting.outputScrolling); this._layoutConfiguration = { ...(compactView ? compactConfigConstants : defaultConfigConstants), @@ -183,7 +185,8 @@ export class NotebookOptions extends Disposable { editorOptionsCustomizations, focusIndicatorGap: 3, interactiveWindowCollapseCodeCells, - markdownFoldHintHeight: 22 + markdownFoldHintHeight: 22, + outputScrolling: outputScrolling }; this._register(this.configurationService.onDidChangeConfiguration(e => { @@ -566,6 +569,7 @@ export class NotebookOptions extends Disposable { outputFontFamily: this._layoutConfiguration.outputFontFamily, markupFontSize: this._layoutConfiguration.markupFontSize, outputLineHeight: this._layoutConfiguration.outputLineHeight, + outputScrolling: this._layoutConfiguration.outputScrolling, }; } @@ -584,6 +588,7 @@ export class NotebookOptions extends Disposable { outputFontFamily: this._layoutConfiguration.outputFontFamily, markupFontSize: this._layoutConfiguration.markupFontSize, outputLineHeight: this._layoutConfiguration.outputLineHeight, + outputScrolling: this._layoutConfiguration.outputScrolling, }; } From a7997f050b89564f1e22627bbb80040c1d9d9a16 Mon Sep 17 00:00:00 2001 From: aamunger Date: Mon, 14 Nov 2022 12:31:58 -0800 Subject: [PATCH 02/11] typed options --- extensions/notebook-renderers/src/index.ts | 13 +++++++++---- .../browser/view/renderers/backLayerWebView.ts | 8 ++++++-- .../browser/view/renderers/webviewPreloads.ts | 13 +++++++++---- .../contrib/notebook/common/notebookCommon.ts | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index adfcf470bc3..f46a4ebbf26 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -28,6 +28,11 @@ interface JavaScriptRenderingHook { preEvaluate(outputItem: OutputItem, element: HTMLElement, script: string, signal: AbortSignal): string | undefined | Promise; } +interface RenderOptions { + readonly lineLimit: number; + readonly outputScrolling: boolean; +} + function clearContainer(container: HTMLElement) { while (container.firstChild) { container.removeChild(container.firstChild); @@ -153,7 +158,7 @@ function renderError(outputInfo: OutputItem, container: HTMLElement, ctx: Render container.classList.add('error'); } -function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boolean, ctx: RendererContext & { readonly settings: { readonly lineLimit: number; readonly outputScrolling: boolean } }): void { +function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boolean, ctx: RendererContext & { readonly settings: RenderOptions }): void { const outputContainer = container.parentElement; if (!outputContainer) { // should never happen @@ -170,7 +175,7 @@ function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boo const text = outputInfo.text(); const element = document.createElement('span'); - insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, true, element); + insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, ctx.settings.outputScrolling, element); outputElement.appendChild(element); return; } @@ -180,7 +185,7 @@ function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boo element.classList.add('output-stream'); const text = outputInfo.text(); - insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, true, element); + insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, ctx.settings.outputScrolling, element); while (container.firstChild) { container.removeChild(container.firstChild); } @@ -205,7 +210,7 @@ export const activate: ActivationFunction = (ctx) => { const htmlHooks = new Set(); const jsHooks = new Set(); - const latestContext = ctx as (RendererContext & { readonly settings: { readonly lineLimit: number; readonly outputScrolling: boolean } }); + const latestContext = ctx as (RendererContext & { readonly settings: RenderOptions }); const style = document.createElement('style'); style.textContent = ` 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 e3a8c13a9f0..d6db3a7d11b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -241,13 +241,17 @@ export class BackLayerWebView extends Themable { private generateContent(coreDependencies: string, baseUrl: string) { const renderersData = this.getRendererData(); const preloadsData = this.getStaticPreloadsData(); + const renderOptions = { + lineLimit: this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30, + outputScrolling: this.configurationService.getValue(NotebookSetting.outputScrolling) ?? true + }; const preloadScript = preloadsScriptStr( this.options, - { dragAndDropEnabled: this.options.dragAndDropEnabled }, // add other options + { dragAndDropEnabled: this.options.dragAndDropEnabled }, + renderOptions, renderersData, preloadsData, this.workspaceTrustManagementService.isWorkspaceTrusted(), - this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30, this.nonce); const enableCsp = this.configurationService.getValue('notebook.experimental.enableCsp'); 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 fe811a05ac9..c11dcaa3975 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -64,14 +64,19 @@ export interface PreloadOptions { dragAndDropEnabled: boolean; } +export interface RenderOptions { + readonly lineLimit: number; + readonly outputScrolling: boolean; +} + interface PreloadContext { readonly nonce: string; readonly style: PreloadStyles; readonly options: PreloadOptions; + readonly renderOptions: RenderOptions; readonly rendererData: readonly webviewMessages.RendererMetadata[]; readonly staticPreloadsData: readonly webviewMessages.StaticPreloadMetadata[]; readonly isWorkspaceTrusted: boolean; - readonly lineLimit: number; } declare function __import(path: string): Promise; @@ -82,7 +87,7 @@ async function webviewPreloads(ctx: PreloadContext) { let currentOptions = ctx.options; let isWorkspaceTrusted = ctx.isWorkspaceTrusted; - const lineLimit = ctx.lineLimit; + const lineLimit = ctx.renderOptions.lineLimit; const acquireVsCodeApi = globalThis.acquireVsCodeApi; const vscode = acquireVsCodeApi(); @@ -2444,14 +2449,14 @@ async function webviewPreloads(ctx: PreloadContext) { }(); } -export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderers: readonly webviewMessages.RendererMetadata[], preloads: readonly webviewMessages.StaticPreloadMetadata[], isWorkspaceTrusted: boolean, lineLimit: number, nonce: string) { +export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderOptions: RenderOptions, renderers: readonly webviewMessages.RendererMetadata[], preloads: readonly webviewMessages.StaticPreloadMetadata[], isWorkspaceTrusted: boolean, nonce: string) { const ctx: PreloadContext = { style: styleValues, options, + renderOptions, rendererData: renderers, staticPreloadsData: preloads, isWorkspaceTrusted, - lineLimit, nonce, }; // TS will try compiling `import()` in webviewPreloads, so use a helper function instead diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index e27d9214e98..a83fee85187 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -927,7 +927,7 @@ export const NotebookSetting = { outputFontSize: 'notebook.outputFontSize', outputFontFamily: 'notebook.outputFontFamily', kernelPickerMRU: 'notebook.experimental.kernelPicker.mru', - outputScrolling: 'notebook.outputScrolling', + outputScrolling: 'notebook.expermental.outputScrolling', } as const; export const enum CellStatusbarAlignment { From 9f5690413836d7af13394a95db1faaf0cca07a88 Mon Sep 17 00:00:00 2001 From: aamunger Date: Mon, 14 Nov 2022 15:39:02 -0800 Subject: [PATCH 03/11] styling --- extensions/notebook-renderers/src/index.ts | 6 ++++-- extensions/notebook-renderers/src/textHelper.ts | 1 + .../notebook/browser/view/renderers/backLayerWebView.ts | 3 +-- .../notebook/browser/view/renderers/webviewPreloads.ts | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index f46a4ebbf26..f9b8de2b5d4 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -231,8 +231,10 @@ export const activate: ActivationFunction = (ctx) => { span.output-stream { display: inline-block; width: 100%; - overflow-y: var(--notebook-output-overflow-y); - max-height: 500px; + } + span.output-stream.scrollable { + overflow-y: scroll; + max-height: 400px; } .output-plaintext .code-bold, .output-stream .code-bold, diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index 6bd93b360dd..b043ae5ae53 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -51,6 +51,7 @@ export function truncatedArrayOfString(id: string, outputs: string[], linesLimit } function scrollableArrayOfString(outputs: string[], container: HTMLElement) { + container.classList.add('scrollable'); const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); const spanElement = handleANSIOutput(buffer.slice(0, 5000).join('\n')); container.appendChild(spanElement); 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 d6db3a7d11b..5af7f304f21 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -234,7 +234,6 @@ export class BackLayerWebView extends Themable { key: 'notebook.error.rendererNotFound', comment: ['$0 is a placeholder for the mime type'] }, "No renderer found for '$0' a"), - 'notebook-output-overflow-y': this.options.outputScrolling ? 'scroll' : 'visible', }; } @@ -243,7 +242,7 @@ export class BackLayerWebView extends Themable { const preloadsData = this.getStaticPreloadsData(); const renderOptions = { lineLimit: this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30, - outputScrolling: this.configurationService.getValue(NotebookSetting.outputScrolling) ?? true + outputScrolling: this.options.outputScrolling }; const preloadScript = preloadsScriptStr( this.options, 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 c11dcaa3975..6c85ef27677 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -88,6 +88,7 @@ async function webviewPreloads(ctx: PreloadContext) { let currentOptions = ctx.options; let isWorkspaceTrusted = ctx.isWorkspaceTrusted; const lineLimit = ctx.renderOptions.lineLimit; + const outputScrolling = ctx.renderOptions.outputScrolling; const acquireVsCodeApi = globalThis.acquireVsCodeApi; const vscode = acquireVsCodeApi(); @@ -216,7 +217,7 @@ async function webviewPreloads(ctx: PreloadContext) { } interface RendererContext extends rendererApi.RendererContext { - readonly settings: { readonly lineLimit: number }; + readonly settings: RenderOptions; } interface RendererModule { @@ -1384,6 +1385,7 @@ async function webviewPreloads(ctx: PreloadContext) { }, settings: { get lineLimit() { return lineLimit; }, + get outputScrolling() { return outputScrolling; }, } }; From ad13c1508d86a229f2a389f12780ae84f9cf39d9 Mon Sep 17 00:00:00 2001 From: aamunger Date: Mon, 14 Nov 2022 16:40:53 -0800 Subject: [PATCH 04/11] setting value --- src/vs/workbench/contrib/notebook/common/notebookCommon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index a83fee85187..88fc8538f7a 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -927,7 +927,7 @@ export const NotebookSetting = { outputFontSize: 'notebook.outputFontSize', outputFontFamily: 'notebook.outputFontFamily', kernelPickerMRU: 'notebook.experimental.kernelPicker.mru', - outputScrolling: 'notebook.expermental.outputScrolling', + outputScrolling: 'notebook.experimental.outputScrolling', } as const; export const enum CellStatusbarAlignment { From d3351f8606d5f5c0d884d5084e67f91fab74b1f1 Mon Sep 17 00:00:00 2001 From: aamunger Date: Tue, 15 Nov 2022 10:28:31 -0800 Subject: [PATCH 05/11] add box shadow for scrolling --- extensions/notebook-renderers/src/index.ts | 9 +++++++++ extensions/notebook-renderers/src/textHelper.ts | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index f9b8de2b5d4..e5fdf09005d 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -236,6 +236,15 @@ export const activate: ActivationFunction = (ctx) => { overflow-y: scroll; max-height: 400px; } + span.output-stream.more-above { + box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset + } + span.output-stream.more-below { + box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset + } + span.output-stream.more-above.more-below { + box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset, var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset + } .output-plaintext .code-bold, .output-stream .code-bold, .traceback .code-bold { diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index b043ae5ae53..8c58ae879cd 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -52,6 +52,22 @@ export function truncatedArrayOfString(id: string, outputs: string[], linesLimit function scrollableArrayOfString(outputs: string[], container: HTMLElement) { container.classList.add('scrollable'); + + container.onscroll = (e) => { + const target = e.target as HTMLElement; + if (target.scrollTop === 0) { + container.classList.remove('more-above'); + } else { + container.classList.add('more-above'); + } + + if (target.scrollTop + target.clientHeight === target.scrollHeight) { + container.classList.remove('more-below'); + } else { + container.classList.add('more-below'); + } + }; + const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); const spanElement = handleANSIOutput(buffer.slice(0, 5000).join('\n')); container.appendChild(spanElement); From 7b5a16bdd1ee78cfb839c264d477823955cdd4fc Mon Sep 17 00:00:00 2001 From: aamunger Date: Tue, 15 Nov 2022 11:08:54 -0800 Subject: [PATCH 06/11] adjustable output height --- extensions/notebook-renderers/src/index.ts | 2 +- .../notebook-renderers/src/textHelper.ts | 61 +++++++++++-------- .../view/renderers/backLayerWebView.ts | 6 +- .../notebook/common/notebookOptions.ts | 7 ++- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index e5fdf09005d..2ebc43cba7c 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -234,7 +234,7 @@ export const activate: ActivationFunction = (ctx) => { } span.output-stream.scrollable { overflow-y: scroll; - max-height: 400px; + max-height: var(--notebook-cell-output-max-height); } span.output-stream.more-above { box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index 8c58ae879cd..86a1734785c 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -5,36 +5,35 @@ import { handleANSIOutput } from './ansi'; -function generateViewMoreElement(outputId: string) { +function generateViewMoreElement(outputId: string, adjustableSize: boolean) { const container = document.createElement('span'); const first = document.createElement('span'); - first.textContent = 'Output exceeds the '; - const second = document.createElement('a'); - second.textContent = 'size limit'; - second.href = `command:workbench.action.openSettings?%5B%22notebook.output.textLineLimit%22%5D`; + + if (adjustableSize) { + first.textContent = 'Output exceeds the '; + const second = document.createElement('a'); + second.textContent = 'size limit'; + second.href = `command:workbench.action.openSettings?%5B%22notebook.output.textLineLimit%22%5D`; + container.appendChild(first); + container.appendChild(second); + } else { + first.textContent = 'Output exceeds the maximium size limit'; + container.appendChild(first); + } + const third = document.createElement('span'); - third.textContent = '. Enable scrolling in the settings, or open the full output data '; + third.textContent = '. Open the full output data '; const forth = document.createElement('a'); forth.textContent = 'in a text editor'; forth.href = `command:workbench.action.openLargeOutput?${outputId}`; - container.appendChild(first); - container.appendChild(second); container.appendChild(third); container.appendChild(forth); return container; } -export function truncatedArrayOfString(id: string, outputs: string[], linesLimit: number, container: HTMLElement) { - const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); +export function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, container: HTMLElement) { const lineCount = buffer.length; - - if (lineCount < linesLimit) { - const spanElement = handleANSIOutput(buffer.slice(0, linesLimit).join('\n')); - container.appendChild(spanElement); - return; - } - - container.appendChild(generateViewMoreElement(id)); + container.appendChild(generateViewMoreElement(id, true)); const div = document.createElement('div'); container.appendChild(div); @@ -50,9 +49,11 @@ export function truncatedArrayOfString(id: string, outputs: string[], linesLimit div2.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'))); } -function scrollableArrayOfString(outputs: string[], container: HTMLElement) { +function scrollableArrayOfString(id: string, buffer: string[], container: HTMLElement) { container.classList.add('scrollable'); + container.classList.add('more-below'); + // disposable? container.onscroll = (e) => { const target = e.target as HTMLElement; if (target.scrollTop === 0) { @@ -68,15 +69,27 @@ function scrollableArrayOfString(outputs: string[], container: HTMLElement) { } }; - const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); - const spanElement = handleANSIOutput(buffer.slice(0, 5000).join('\n')); - container.appendChild(spanElement); + if (buffer.length > 5000) { + container.appendChild(generateViewMoreElement(id, false)); + } + const div = document.createElement('div'); + container.appendChild(div); + div.appendChild(handleANSIOutput(buffer.slice(0, 5000).join('\n'))); } export function insertOutput(id: string, outputs: string[], linesLimit: number, scrollable: boolean, container: HTMLElement) { + const buffer = outputs.join('\n').split(/\r\n|\r|\n/g); + const lineCount = buffer.length; + + if (lineCount < linesLimit) { + const spanElement = handleANSIOutput(buffer.join('\n')); + container.appendChild(spanElement); + return; + } + if (scrollable) { - scrollableArrayOfString(outputs, container); + scrollableArrayOfString(id, buffer, container); } else { - truncatedArrayOfString(id, outputs, linesLimit, container); + truncatedArrayOfString(id, buffer, linesLimit, container); } } 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 5af7f304f21..9e1dd01db2d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -38,7 +38,7 @@ import { NOTEBOOK_WEBVIEW_BOUNDARY } from 'vs/workbench/contrib/notebook/browser import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; -import { CellUri, INotebookRendererInfo, NotebookSetting, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellUri, INotebookRendererInfo, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { IScopedRendererMessaging } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -98,6 +98,7 @@ interface BacklayerWebviewOptions { readonly markupFontSize: number; readonly outputLineHeight: number; readonly outputScrolling: boolean; + readonly outputLineLimit: number; } export class BackLayerWebView extends Themable { @@ -228,6 +229,7 @@ export class BackLayerWebView extends Themable { 'notebook-markup-font-size': typeof this.options.markupFontSize === 'number' && this.options.markupFontSize > 0 ? `${this.options.markupFontSize}px` : `calc(${this.options.fontSize}px * 1.2)`, 'notebook-cell-output-font-size': `${this.options.outputFontSize || this.options.fontSize}px`, 'notebook-cell-output-line-height': `${this.options.outputLineHeight}px`, + 'notebook-cell-output-max-height': `${this.options.outputLineHeight * this.options.outputLineLimit}px`, 'notebook-cell-output-font-family': this.options.outputFontFamily || this.options.fontFamily, 'notebook-cell-markup-empty-content': nls.localize('notebook.emptyMarkdownPlaceholder', "Empty markdown cell, double click or press enter to edit."), 'notebook-cell-renderer-not-found-error': nls.localize({ @@ -241,7 +243,7 @@ export class BackLayerWebView extends Themable { const renderersData = this.getRendererData(); const preloadsData = this.getStaticPreloadsData(); const renderOptions = { - lineLimit: this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30, + lineLimit: this.options.outputLineLimit, outputScrolling: this.options.outputScrolling }; const preloadScript = preloadsScriptStr( diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 19786b0af3f..ae0b576b5d8 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -71,6 +71,7 @@ export interface NotebookLayoutConfiguration { focusIndicatorGap: number; interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells; outputScrolling: boolean; + outputLineLimit: number; } export interface NotebookOptionsChangeEvent { @@ -149,6 +150,7 @@ export class NotebookOptions extends Disposable { const interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells); const outputLineHeight = this._computeOutputLineHeight(); const outputScrolling = this.configurationService.getValue(NotebookSetting.outputScrolling); + const outputLineLimit = this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30; this._layoutConfiguration = { ...(compactView ? compactConfigConstants : defaultConfigConstants), @@ -186,7 +188,8 @@ export class NotebookOptions extends Disposable { focusIndicatorGap: 3, interactiveWindowCollapseCodeCells, markdownFoldHintHeight: 22, - outputScrolling: outputScrolling + outputScrolling: outputScrolling, + outputLineLimit: outputLineLimit }; this._register(this.configurationService.onDidChangeConfiguration(e => { @@ -570,6 +573,7 @@ export class NotebookOptions extends Disposable { markupFontSize: this._layoutConfiguration.markupFontSize, outputLineHeight: this._layoutConfiguration.outputLineHeight, outputScrolling: this._layoutConfiguration.outputScrolling, + outputLineLimit: this._layoutConfiguration.outputLineLimit, }; } @@ -589,6 +593,7 @@ export class NotebookOptions extends Disposable { markupFontSize: this._layoutConfiguration.markupFontSize, outputLineHeight: this._layoutConfiguration.outputLineHeight, outputScrolling: this._layoutConfiguration.outputScrolling, + outputLineLimit: this._layoutConfiguration.outputLineLimit, }; } From 457e4d29dabf77ce378de65d56065d9486509749 Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 16 Nov 2022 10:50:59 -0800 Subject: [PATCH 07/11] update css selectors --- extensions/notebook-renderers/src/index.ts | 24 +++++++++---------- .../notebook-renderers/src/textHelper.ts | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 2ebc43cba7c..7b4cb12a8df 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-notebook-renderer'; -import { insertOutput, truncatedArrayOfString } from './textHelper'; +import { insertOutput } from './textHelper'; interface IDisposable { dispose(): void; @@ -125,7 +125,7 @@ async function renderJavascript(outputInfo: OutputItem, container: HTMLElement, domEval(element); } -function renderError(outputInfo: OutputItem, container: HTMLElement, ctx: RendererContext & { readonly settings: { readonly lineLimit: number } }): void { +function renderError(outputInfo: OutputItem, container: HTMLElement, ctx: RendererContext & { readonly settings: RenderOptions }): void { const element = document.createElement('div'); container.appendChild(element); type ErrorLike = Partial; @@ -143,7 +143,7 @@ function renderError(outputInfo: OutputItem, container: HTMLElement, ctx: Render stack.classList.add('traceback'); stack.style.margin = '8px 0'; const element = document.createElement('span'); - truncatedArrayOfString(outputInfo.id, [err.stack ?? ''], ctx.settings.lineLimit, element); + insertOutput(outputInfo.id, [err.stack ?? ''], ctx.settings.lineLimit, false, element); stack.appendChild(element); container.appendChild(stack); } else { @@ -196,12 +196,12 @@ function renderStream(outputInfo: OutputItem, container: HTMLElement, error: boo } } -function renderText(outputInfo: OutputItem, container: HTMLElement, ctx: RendererContext & { readonly settings: { readonly lineLimit: number } }): void { +function renderText(outputInfo: OutputItem, container: HTMLElement, ctx: RendererContext & { readonly settings: RenderOptions }): void { clearContainer(container); const contentNode = document.createElement('div'); contentNode.classList.add('output-plaintext'); const text = outputInfo.text(); - truncatedArrayOfString(outputInfo.id, [text], ctx.settings.lineLimit, contentNode); + insertOutput(outputInfo.id, [text], ctx.settings.lineLimit, ctx.settings.outputScrolling, contentNode); container.appendChild(contentNode); } @@ -217,6 +217,8 @@ export const activate: ActivationFunction = (ctx) => { .output-plaintext, .output-stream, .traceback { + display: inline-block; + width: 100%; line-height: var(--notebook-cell-output-line-height); font-family: var(--notebook-cell-output-font-family); white-space: pre-wrap; @@ -228,21 +230,17 @@ export const activate: ActivationFunction = (ctx) => { -ms-user-select: text; cursor: auto; } - span.output-stream { - display: inline-block; - width: 100%; - } - span.output-stream.scrollable { + .output > span.scrollable { overflow-y: scroll; max-height: var(--notebook-cell-output-max-height); } - span.output-stream.more-above { + .output > span.output-stream.more-above { box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset } - span.output-stream.more-below { + .output > span.output-stream.more-below { box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset } - span.output-stream.more-above.more-below { + .output > span.output-stream.more-above.more-below { box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset, var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset } .output-plaintext .code-bold, diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index 86a1734785c..a57545afb45 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -31,7 +31,7 @@ function generateViewMoreElement(outputId: string, adjustableSize: boolean) { return container; } -export function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, container: HTMLElement) { +function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, container: HTMLElement) { const lineCount = buffer.length; container.appendChild(generateViewMoreElement(id, true)); From b3f3de9cfe35eac3b38ffefc4b1d7f5944dc2205 Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 16 Nov 2022 16:20:07 -0800 Subject: [PATCH 08/11] border around scrollable area --- extensions/notebook-renderers/src/index.ts | 15 ++++++--------- extensions/notebook-renderers/src/textHelper.ts | 17 ----------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 7b4cb12a8df..2a0bba7c132 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -230,18 +230,15 @@ export const activate: ActivationFunction = (ctx) => { -ms-user-select: text; cursor: auto; } + .output > span.scrollable { overflow-y: scroll; max-height: var(--notebook-cell-output-max-height); - } - .output > span.output-stream.more-above { - box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset - } - .output > span.output-stream.more-below { - box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset - } - .output > span.output-stream.more-above.more-below { - box-shadow: var(--vscode-scrollbar-shadow) 0px -6px 6px -6px inset, var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset + border: var(--vscode-editorWidget-border); + border-style: solid; + padding-left: 4px; + margin-left: -4px; + margin-right: -4px; } .output-plaintext .code-bold, .output-stream .code-bold, diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index a57545afb45..47b638fe0dd 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -51,23 +51,6 @@ function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number function scrollableArrayOfString(id: string, buffer: string[], container: HTMLElement) { container.classList.add('scrollable'); - container.classList.add('more-below'); - - // disposable? - container.onscroll = (e) => { - const target = e.target as HTMLElement; - if (target.scrollTop === 0) { - container.classList.remove('more-above'); - } else { - container.classList.add('more-above'); - } - - if (target.scrollTop + target.clientHeight === target.scrollHeight) { - container.classList.remove('more-below'); - } else { - container.classList.add('more-below'); - } - }; if (buffer.length > 5000) { container.appendChild(generateViewMoreElement(id, false)); From 708ec07316f1a3bccfba592142adf055c810edc4 Mon Sep 17 00:00:00 2001 From: aamunger Date: Thu, 17 Nov 2022 15:50:25 -0800 Subject: [PATCH 09/11] thin border, no word wrap --- extensions/notebook-renderers/src/index.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 2a0bba7c132..95248ea5a40 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -221,24 +221,25 @@ export const activate: ActivationFunction = (ctx) => { width: 100%; line-height: var(--notebook-cell-output-line-height); font-family: var(--notebook-cell-output-font-family); - white-space: pre-wrap; - word-wrap: break-word; - font-size: var(--notebook-cell-output-font-size); user-select: text; -webkit-user-select: text; -ms-user-select: text; cursor: auto; } - + output-plaintext, + .traceback { + white-space: pre-wrap; + word-wrap: break-word; + } .output > span.scrollable { overflow-y: scroll; max-height: var(--notebook-cell-output-max-height); border: var(--vscode-editorWidget-border); border-style: solid; padding-left: 4px; - margin-left: -4px; - margin-right: -4px; + box-sizing: border-box; + border-width: 1px; } .output-plaintext .code-bold, .output-stream .code-bold, From 37b985e049b495f825f1a198fc997d4b9b690912 Mon Sep 17 00:00:00 2001 From: aamunger Date: Thu, 17 Nov 2022 16:36:31 -0800 Subject: [PATCH 10/11] fix --- src/vs/workbench/contrib/notebook/common/notebookCommon.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 88fc8538f7a..fc38714bcef 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -926,6 +926,7 @@ export const NotebookSetting = { outputLineHeight: 'notebook.outputLineHeight', outputFontSize: 'notebook.outputFontSize', outputFontFamily: 'notebook.outputFontFamily', + kernelPickerType: 'notebook.kernelPickerType', kernelPickerMRU: 'notebook.experimental.kernelPicker.mru', outputScrolling: 'notebook.experimental.outputScrolling', } as const; From b380ef5bfa372733d4f817b7046f649b6ff95dc7 Mon Sep 17 00:00:00 2001 From: aamunger Date: Fri, 18 Nov 2022 08:11:39 -0800 Subject: [PATCH 11/11] undo bad change --- src/vs/workbench/contrib/notebook/common/notebookCommon.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index fc38714bcef..d747b37e22d 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -926,8 +926,7 @@ export const NotebookSetting = { outputLineHeight: 'notebook.outputLineHeight', outputFontSize: 'notebook.outputFontSize', outputFontFamily: 'notebook.outputFontFamily', - kernelPickerType: 'notebook.kernelPickerType', - kernelPickerMRU: 'notebook.experimental.kernelPicker.mru', + kernelPickerType: 'notebook.kernelPicker.type', outputScrolling: 'notebook.experimental.outputScrolling', } as const;