From b401865957ad88b4992c52af08e930f5cb88c059 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:53:16 -0700 Subject: [PATCH] More clean up, doc updating vs/base --- ...d_used_files.js => vs_base_find_unused.js} | 18 +- ...{update_vs_base.ps1 => vs_base_update.ps1} | 0 src/vs/README.md | 20 +- src/vs/base/browser/performance.ts | 272 ------------------ src/vs/base/browser/pixelRatio.ts | 114 -------- src/vs/base/browser/trustedTypes.ts | 35 --- .../browser/ui/scrollbar/media/scrollbars.css | 72 ----- 7 files changed, 34 insertions(+), 497 deletions(-) rename bin/{vs_base_find_used_files.js => vs_base_find_unused.js} (54%) rename bin/{update_vs_base.ps1 => vs_base_update.ps1} (100%) delete mode 100644 src/vs/base/browser/performance.ts delete mode 100644 src/vs/base/browser/pixelRatio.ts delete mode 100644 src/vs/base/browser/trustedTypes.ts delete mode 100644 src/vs/base/browser/ui/scrollbar/media/scrollbars.css diff --git a/bin/vs_base_find_used_files.js b/bin/vs_base_find_unused.js similarity index 54% rename from bin/vs_base_find_used_files.js rename to bin/vs_base_find_unused.js index 50ffaf4f..572cca09 100644 --- a/bin/vs_base_find_used_files.js +++ b/bin/vs_base_find_unused.js @@ -2,6 +2,7 @@ const { dirname } = require("path"); const ts = require("typescript"); +const fs = require("fs"); function findUnusedSymbols( /** @type string */ tsconfigPath @@ -17,7 +18,22 @@ function findUnusedSymbols( }); const sourceFiles = program.getSourceFiles(); const usedBaseSourceFiles = sourceFiles.filter(e => e.fileName.includes('src/vs/base/')); - console.log('Source files used in src/vs/base/:', usedBaseSourceFiles.map(e => e.fileName.replace(/^.+\/src\//, 'src/')).sort((a, b) => a.localeCompare(b))); + const usedFilesInBase = usedBaseSourceFiles.map(e => e.fileName.replace(/^.+\/src\//, 'src/')).sort((a, b) => a.localeCompare(b)); + // console.log('Source files used in src/vs/base/:', used); + + // Get an array of all files that exist in src/vs/base/ + const allFilesInBase = ( + fs.readdirSync('src/vs/base', { recursive: true, withFileTypes: true }) + .filter(e => e.isFile()) + .map(e => `${e.parentPath}/${e.name}`.replace(/\\/g, '/')) + ); + const unusedFilesInBase = allFilesInBase.filter(e => !usedFilesInBase.includes(e)); + + console.log({ + allFilesInBase, + usedFilesInBase, + unusedFilesInBase + }); } // Example usage diff --git a/bin/update_vs_base.ps1 b/bin/vs_base_update.ps1 similarity index 100% rename from bin/update_vs_base.ps1 rename to bin/vs_base_update.ps1 diff --git a/src/vs/README.md b/src/vs/README.md index 002749b3..860ba53e 100644 --- a/src/vs/README.md +++ b/src/vs/README.md @@ -1,9 +1,23 @@ This folder contains the `base/` module from the [Visual Studio Code repository](https://github.com/microsoft/vscode) which has many helpers that are useful to xterm.js. -To update against upstream: +Rarely we want to update these sources when an important bug is fixed upstream or when there is a new feature we want to leverage. To update against upstream: ``` -./bin/update_vs_base.ps1 +./bin/vs_base_update.ps1 ``` -TODO: Mention review `src/vs/base` in xterm.js +If new functions are being used from the project then import them from another project. + +Before committing we need to clean up the diff so that files that aren't being used are not inlcuded. The following script uses the typescript compiler to find any files that are not being imported into the project: + +``` +node ./bin/vs_base_find_unused.js +``` + +The last step is to do a once over of the resulting bundled xterm.js file to ensure it isn't too large: + +1. Run `yarn esbuild` +2. Open up `xterm.mjs` +3. Search for `src/vs/base/` + +This will show you all the parts of base that will be included in the final minified bundle. Unfortunately tree shaking doesn't find everything, be on the lookout for large arrays or classes that aren't being used. If your editor has find decorations in the scroll bar it's easy to find which parts of base are consuming a lot of lines. diff --git a/src/vs/base/browser/performance.ts b/src/vs/base/browser/performance.ts deleted file mode 100644 index dab46447..00000000 --- a/src/vs/base/browser/performance.ts +++ /dev/null @@ -1,272 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export namespace inputLatency { - - // Measurements are recorded as totals, the average is calculated when the final measurements - // are created. - interface ICumulativeMeasurement { - total: number; - min: number; - max: number; - } - const totalKeydownTime: ICumulativeMeasurement = { total: 0, min: Number.MAX_VALUE, max: 0 }; - const totalInputTime: ICumulativeMeasurement = { ...totalKeydownTime }; - const totalRenderTime: ICumulativeMeasurement = { ...totalKeydownTime }; - const totalInputLatencyTime: ICumulativeMeasurement = { ...totalKeydownTime }; - let measurementsCount = 0; - - - - // The state of each event, this helps ensure the integrity of the measurement and that - // something unexpected didn't happen that could skew the measurement. - const enum EventPhase { - Before = 0, - InProgress = 1, - Finished = 2 - } - const state = { - keydown: EventPhase.Before, - input: EventPhase.Before, - render: EventPhase.Before, - }; - - /** - * Record the start of the keydown event. - */ - export function onKeyDown() { - /** Direct Check C. See explanation in {@link recordIfFinished} */ - recordIfFinished(); - performance.mark('inputlatency/start'); - performance.mark('keydown/start'); - state.keydown = EventPhase.InProgress; - queueMicrotask(markKeyDownEnd); - } - - /** - * Mark the end of the keydown event. - */ - function markKeyDownEnd() { - if (state.keydown === EventPhase.InProgress) { - performance.mark('keydown/end'); - state.keydown = EventPhase.Finished; - } - } - - /** - * Record the start of the beforeinput event. - */ - export function onBeforeInput() { - performance.mark('input/start'); - state.input = EventPhase.InProgress; - /** Schedule Task A. See explanation in {@link recordIfFinished} */ - scheduleRecordIfFinishedTask(); - } - - /** - * Record the start of the input event. - */ - export function onInput() { - if (state.input === EventPhase.Before) { - // it looks like we didn't receive a `beforeinput` - onBeforeInput(); - } - queueMicrotask(markInputEnd); - } - - function markInputEnd() { - if (state.input === EventPhase.InProgress) { - performance.mark('input/end'); - state.input = EventPhase.Finished; - } - } - - /** - * Record the start of the keyup event. - */ - export function onKeyUp() { - /** Direct Check D. See explanation in {@link recordIfFinished} */ - recordIfFinished(); - } - - /** - * Record the start of the selectionchange event. - */ - export function onSelectionChange() { - /** Direct Check E. See explanation in {@link recordIfFinished} */ - recordIfFinished(); - } - - /** - * Record the start of the animation frame performing the rendering. - */ - export function onRenderStart() { - // Render may be triggered during input, but we only measure the following animation frame - if (state.keydown === EventPhase.Finished && state.input === EventPhase.Finished && state.render === EventPhase.Before) { - // Only measure the first render after keyboard input - performance.mark('render/start'); - state.render = EventPhase.InProgress; - queueMicrotask(markRenderEnd); - /** Schedule Task B. See explanation in {@link recordIfFinished} */ - scheduleRecordIfFinishedTask(); - } - } - - /** - * Mark the end of the animation frame performing the rendering. - */ - function markRenderEnd() { - if (state.render === EventPhase.InProgress) { - performance.mark('render/end'); - state.render = EventPhase.Finished; - } - } - - function scheduleRecordIfFinishedTask() { - // Here we can safely assume that the `setTimeout` will not be - // artificially delayed by 4ms because we schedule it from - // event handlers - setTimeout(recordIfFinished); - } - - /** - * Record the input latency sample if input handling and rendering are finished. - * - * The challenge here is that we want to record the latency in such a way that it includes - * also the layout and painting work the browser does during the animation frame task. - * - * Simply scheduling a new task (via `setTimeout`) from the animation frame task would - * schedule the new task at the end of the task queue (after other code that uses `setTimeout`), - * so we need to use multiple strategies to make sure our task runs before others: - * - * We schedule tasks (A and B): - * - we schedule a task A (via a `setTimeout` call) when the input starts in `markInputStart`. - * If the animation frame task is scheduled quickly by the browser, then task A has a very good - * chance of being the very first task after the animation frame and thus will record the input latency. - * - however, if the animation frame task is scheduled a bit later, then task A might execute - * before the animation frame task. We therefore schedule another task B from `markRenderStart`. - * - * We do direct checks in browser event handlers (C, D, E): - * - if the browser has multiple keydown events queued up, they will be scheduled before the `setTimeout` tasks, - * so we do a direct check in the keydown event handler (C). - * - depending on timing, sometimes the animation frame is scheduled even before the `keyup` event, so we - * do a direct check there too (E). - * - the browser oftentimes emits a `selectionchange` event after an `input`, so we do a direct check there (D). - */ - function recordIfFinished() { - if (state.keydown === EventPhase.Finished && state.input === EventPhase.Finished && state.render === EventPhase.Finished) { - performance.mark('inputlatency/end'); - - performance.measure('keydown', 'keydown/start', 'keydown/end'); - performance.measure('input', 'input/start', 'input/end'); - performance.measure('render', 'render/start', 'render/end'); - performance.measure('inputlatency', 'inputlatency/start', 'inputlatency/end'); - - addMeasure('keydown', totalKeydownTime); - addMeasure('input', totalInputTime); - addMeasure('render', totalRenderTime); - addMeasure('inputlatency', totalInputLatencyTime); - - // console.info( - // `input latency=${performance.getEntriesByName('inputlatency')[0].duration.toFixed(1)} [` + - // `keydown=${performance.getEntriesByName('keydown')[0].duration.toFixed(1)}, ` + - // `input=${performance.getEntriesByName('input')[0].duration.toFixed(1)}, ` + - // `render=${performance.getEntriesByName('render')[0].duration.toFixed(1)}` + - // `]` - // ); - - measurementsCount++; - - reset(); - } - } - - function addMeasure(entryName: string, cumulativeMeasurement: ICumulativeMeasurement): void { - const duration = performance.getEntriesByName(entryName)[0].duration; - cumulativeMeasurement.total += duration; - cumulativeMeasurement.min = Math.min(cumulativeMeasurement.min, duration); - cumulativeMeasurement.max = Math.max(cumulativeMeasurement.max, duration); - } - - /** - * Clear the current sample. - */ - function reset() { - performance.clearMarks('keydown/start'); - performance.clearMarks('keydown/end'); - performance.clearMarks('input/start'); - performance.clearMarks('input/end'); - performance.clearMarks('render/start'); - performance.clearMarks('render/end'); - performance.clearMarks('inputlatency/start'); - performance.clearMarks('inputlatency/end'); - - performance.clearMeasures('keydown'); - performance.clearMeasures('input'); - performance.clearMeasures('render'); - performance.clearMeasures('inputlatency'); - - state.keydown = EventPhase.Before; - state.input = EventPhase.Before; - state.render = EventPhase.Before; - } - - export interface IInputLatencyMeasurements { - keydown: IInputLatencySingleMeasurement; - input: IInputLatencySingleMeasurement; - render: IInputLatencySingleMeasurement; - total: IInputLatencySingleMeasurement; - sampleCount: number; - } - - export interface IInputLatencySingleMeasurement { - average: number; - min: number; - max: number; - } - - /** - * Gets all input latency samples and clears the internal buffers to start recording a new set - * of samples. - */ - export function getAndClearMeasurements(): IInputLatencyMeasurements | undefined { - if (measurementsCount === 0) { - return undefined; - } - - // Assemble the result - const result = { - keydown: cumulativeToFinalMeasurement(totalKeydownTime), - input: cumulativeToFinalMeasurement(totalInputTime), - render: cumulativeToFinalMeasurement(totalRenderTime), - total: cumulativeToFinalMeasurement(totalInputLatencyTime), - sampleCount: measurementsCount - }; - - // Clear the cumulative measurements - clearCumulativeMeasurement(totalKeydownTime); - clearCumulativeMeasurement(totalInputTime); - clearCumulativeMeasurement(totalRenderTime); - clearCumulativeMeasurement(totalInputLatencyTime); - measurementsCount = 0; - - return result; - } - - function cumulativeToFinalMeasurement(cumulative: ICumulativeMeasurement): IInputLatencySingleMeasurement { - return { - average: cumulative.total / measurementsCount, - max: cumulative.max, - min: cumulative.min, - }; - } - - function clearCumulativeMeasurement(cumulative: ICumulativeMeasurement): void { - cumulative.total = 0; - cumulative.min = Number.MAX_VALUE; - cumulative.max = 0; - } - -} diff --git a/src/vs/base/browser/pixelRatio.ts b/src/vs/base/browser/pixelRatio.ts deleted file mode 100644 index 197a802f..00000000 --- a/src/vs/base/browser/pixelRatio.ts +++ /dev/null @@ -1,114 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { getWindowId, onDidUnregisterWindow } from 'vs/base/browser/dom'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, markAsSingleton } from 'vs/base/common/lifecycle'; - -/** - * See https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes - */ -class DevicePixelRatioMonitor extends Disposable { - - private readonly _onDidChange = this._register(new Emitter()); - readonly onDidChange = this._onDidChange.event; - - private readonly _listener: () => void; - private _mediaQueryList: MediaQueryList | null; - - constructor(targetWindow: Window) { - super(); - - this._listener = () => this._handleChange(targetWindow, true); - this._mediaQueryList = null; - this._handleChange(targetWindow, false); - } - - private _handleChange(targetWindow: Window, fireEvent: boolean): void { - this._mediaQueryList?.removeEventListener('change', this._listener); - - this._mediaQueryList = targetWindow.matchMedia(`(resolution: ${targetWindow.devicePixelRatio}dppx)`); - this._mediaQueryList.addEventListener('change', this._listener); - - if (fireEvent) { - this._onDidChange.fire(); - } - } -} - -export interface IPixelRatioMonitor { - readonly value: number; - readonly onDidChange: Event; -} - -class PixelRatioMonitorImpl extends Disposable implements IPixelRatioMonitor { - - private readonly _onDidChange = this._register(new Emitter()); - readonly onDidChange = this._onDidChange.event; - - private _value: number; - - get value(): number { - return this._value; - } - - constructor(targetWindow: Window) { - super(); - - this._value = this._getPixelRatio(targetWindow); - - const dprMonitor = this._register(new DevicePixelRatioMonitor(targetWindow)); - this._register(dprMonitor.onDidChange(() => { - this._value = this._getPixelRatio(targetWindow); - this._onDidChange.fire(this._value); - })); - } - - private _getPixelRatio(targetWindow: Window): number { - const ctx: any = document.createElement('canvas').getContext('2d'); - const dpr = targetWindow.devicePixelRatio || 1; - const bsr = ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1; - return dpr / bsr; - } -} - -class PixelRatioMonitorFacade { - - private readonly mapWindowIdToPixelRatioMonitor = new Map(); - - private _getOrCreatePixelRatioMonitor(targetWindow: Window): PixelRatioMonitorImpl { - const targetWindowId = getWindowId(targetWindow); - let pixelRatioMonitor = this.mapWindowIdToPixelRatioMonitor.get(targetWindowId); - if (!pixelRatioMonitor) { - pixelRatioMonitor = markAsSingleton(new PixelRatioMonitorImpl(targetWindow)); - this.mapWindowIdToPixelRatioMonitor.set(targetWindowId, pixelRatioMonitor); - - markAsSingleton(Event.once(onDidUnregisterWindow)(({ vscodeWindowId }) => { - if (vscodeWindowId === targetWindowId) { - pixelRatioMonitor?.dispose(); - this.mapWindowIdToPixelRatioMonitor.delete(targetWindowId); - } - })); - } - return pixelRatioMonitor; - } - - getInstance(targetWindow: Window): IPixelRatioMonitor { - return this._getOrCreatePixelRatioMonitor(targetWindow); - } -} - -/** - * Returns the pixel ratio. - * - * This is useful for rendering elements at native screen resolution or for being used as - * a cache key when storing font measurements. Fonts might render differently depending on resolution - * and any measurements need to be discarded for example when a window is moved from a monitor to another. - */ -export const PixelRatio = new PixelRatioMonitorFacade(); diff --git a/src/vs/base/browser/trustedTypes.ts b/src/vs/base/browser/trustedTypes.ts deleted file mode 100644 index 0ef4b084..00000000 --- a/src/vs/base/browser/trustedTypes.ts +++ /dev/null @@ -1,35 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { onUnexpectedError } from 'vs/base/common/errors'; - -export function createTrustedTypesPolicy( - policyName: string, - policyOptions?: Options, -): undefined | Pick, 'name' | Extract> { - - interface IMonacoEnvironment { - createTrustedTypesPolicy( - policyName: string, - policyOptions?: Options, - ): undefined | Pick, 'name' | Extract>; - } - const monacoEnvironment: IMonacoEnvironment | undefined = (globalThis as any).MonacoEnvironment; - - if (monacoEnvironment?.createTrustedTypesPolicy) { - try { - return monacoEnvironment.createTrustedTypesPolicy(policyName, policyOptions); - } catch (err) { - onUnexpectedError(err); - return undefined; - } - } - try { - return (globalThis as any).trustedTypes?.createPolicy(policyName, policyOptions); - } catch (err) { - onUnexpectedError(err); - return undefined; - } -} diff --git a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css deleted file mode 100644 index 84c17370..00000000 --- a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css +++ /dev/null @@ -1,72 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Arrows */ -.monaco-scrollable-element > .scrollbar > .scra { - cursor: pointer; - font-size: 11px !important; -} - -.monaco-scrollable-element > .visible { - opacity: 1; - - /* Background rule added for IE9 - to allow clicks on dom node */ - background:rgba(0,0,0,0); - - transition: opacity 100ms linear; - /* In front of peek view */ - z-index: 11; -} -.monaco-scrollable-element > .invisible { - opacity: 0; - pointer-events: none; -} -.monaco-scrollable-element > .invisible.fade { - transition: opacity 800ms linear; -} - -/* Scrollable Content Inset Shadow */ -.monaco-scrollable-element > .shadow { - position: absolute; - display: none; -} -.monaco-scrollable-element > .shadow.top { - display: block; - top: 0; - left: 3px; - height: 3px; - width: 100%; - box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset; -} -.monaco-scrollable-element > .shadow.left { - display: block; - top: 3px; - left: 0; - height: 100%; - width: 3px; - box-shadow: var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset; -} -.monaco-scrollable-element > .shadow.top-left-corner { - display: block; - top: 0; - left: 0; - height: 3px; - width: 3px; -} -.monaco-scrollable-element > .shadow.top.left { - box-shadow: var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset; -} - -.monaco-scrollable-element > .scrollbar > .slider { - background: var(--vscode-scrollbarSlider-background); -} - -.monaco-scrollable-element > .scrollbar > .slider:hover { - background: var(--vscode-scrollbarSlider-hoverBackground); -} - -.monaco-scrollable-element > .scrollbar > .slider.active { - background: var(--vscode-scrollbarSlider-activeBackground); -}