Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
369ca9b525 | ||
|
|
a5422d1b11 | ||
|
|
c2890d8a4d | ||
|
|
7a7abddc45 | ||
|
|
8c71bfd65f | ||
|
|
3c2b911439 | ||
|
|
5ee8760418 |
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { IColorContrastCache } from 'browser/Types';
|
import { IColorContrastCache } from 'browser/Types';
|
||||||
import { DIM_OPACITY, TEXT_BASELINE } from './Constants';
|
import { DIM_OPACITY, TEXT_BASELINE } from './Constants';
|
||||||
import { tryDrawCustomGlyph } from './customGlyphs/CustomGlyphRasterizer';
|
import { loadCustomGlyphDefinitions, tryDrawCustomGlyph } from './customGlyphs/CustomGlyphRasterizer';
|
||||||
import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
||||||
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from './Types';
|
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from './Types';
|
||||||
import { NULL_COLOR, channels, color, rgba } from 'common/Color';
|
import { NULL_COLOR, channels, color, rgba } from 'common/Color';
|
||||||
@@ -100,6 +100,10 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
alpha: this._config.allowTransparency,
|
alpha: this._config.allowTransparency,
|
||||||
willReadFrequently: true
|
willReadFrequently: true
|
||||||
}));
|
}));
|
||||||
|
// Start loading custom glyph definitions asynchronously if custom glyphs are enabled
|
||||||
|
if (this._config.customGlyphs !== false) {
|
||||||
|
loadCustomGlyphDefinitions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
|||||||
@@ -4,8 +4,38 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
||||||
import { customGlyphDefinitions } from './CustomGlyphDefinitions';
|
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphCharacterDefinition, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
||||||
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
|
||||||
|
/**
|
||||||
|
* Cached custom glyph definitions. This is loaded dynamically to support code splitting.
|
||||||
|
*/
|
||||||
|
let customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefinition | undefined } | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise that resolves when custom glyph definitions are loaded.
|
||||||
|
*/
|
||||||
|
let loadingPromise: Promise<void> | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begins loading the custom glyph definitions. This should be called as early as possible
|
||||||
|
* to ensure the definitions are ready when needed.
|
||||||
|
* @returns A promise that resolves when the definitions are loaded.
|
||||||
|
*/
|
||||||
|
export function loadCustomGlyphDefinitions(): Promise<void> {
|
||||||
|
if (customGlyphDefinitions) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
if (!loadingPromise) {
|
||||||
|
loadingPromise = import('./CustomGlyphDefinitions').then(module => {
|
||||||
|
customGlyphDefinitions = module.customGlyphDefinitions;
|
||||||
|
}).catch(err => {
|
||||||
|
// Reset the loading promise on failure to allow retry
|
||||||
|
loadingPromise = undefined;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return loadingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try drawing a custom block element or box drawing character, returning whether it was
|
* Try drawing a custom block element or box drawing character, returning whether it was
|
||||||
@@ -24,6 +54,11 @@ export function tryDrawCustomGlyph(
|
|||||||
devicePixelRatio: number,
|
devicePixelRatio: number,
|
||||||
backgroundColor?: string
|
backgroundColor?: string
|
||||||
): boolean {
|
): boolean {
|
||||||
|
// If definitions are not loaded yet, return false to fall back to font rendering
|
||||||
|
if (!customGlyphDefinitions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const unifiedCharDefinition = customGlyphDefinitions[c];
|
const unifiedCharDefinition = customGlyphDefinitions[c];
|
||||||
if (unifiedCharDefinition) {
|
if (unifiedCharDefinition) {
|
||||||
// Normalize to array for uniform handling
|
// Normalize to array for uniform handling
|
||||||
|
|||||||
+15
-4
@@ -26,7 +26,10 @@ const commonOptions = {
|
|||||||
target: 'es2021',
|
target: 'es2021',
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
treeShaking: true,
|
treeShaking: true,
|
||||||
|
splitting: true,
|
||||||
|
chunkNames: 'chunks/[name]-[hash]',
|
||||||
logLevel: 'warning',
|
logLevel: 'warning',
|
||||||
|
outExtension: { '.js': '.mjs' },
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @type {esbuild.BuildOptions} */
|
/** @type {esbuild.BuildOptions} */
|
||||||
@@ -103,7 +106,8 @@ if (config.addon) {
|
|||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`addons/addon-${config.addon}/src/${getAddonEntryPoint(config.addon)}.ts`],
|
entryPoints: [`addons/addon-${config.addon}/src/${getAddonEntryPoint(config.addon)}.ts`],
|
||||||
outfile: `addons/addon-${config.addon}/lib/addon-${config.addon}.mjs`,
|
outdir: `addons/addon-${config.addon}/lib`,
|
||||||
|
entryNames: `addon-${config.addon}`,
|
||||||
};
|
};
|
||||||
outConfig = {
|
outConfig = {
|
||||||
...outConfig,
|
...outConfig,
|
||||||
@@ -128,7 +132,8 @@ if (config.addon) {
|
|||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`demo/client/client.ts`],
|
entryPoints: [`demo/client/client.ts`],
|
||||||
outfile: 'demo/dist/client-bundle.js',
|
outdir: 'demo/dist',
|
||||||
|
entryNames: 'client-bundle',
|
||||||
external: ['util', 'os', 'fs', 'path', 'stream', 'Terminal'],
|
external: ['util', 'os', 'fs', 'path', 'stream', 'Terminal'],
|
||||||
alias: {
|
alias: {
|
||||||
// Library ESM imports
|
// Library ESM imports
|
||||||
@@ -164,6 +169,10 @@ if (config.addon) {
|
|||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
platform: 'node',
|
platform: 'node',
|
||||||
external: ['node-pty'],
|
external: ['node-pty'],
|
||||||
|
// Splitting is not compatible with cjs format
|
||||||
|
splitting: false,
|
||||||
|
// Override the .mjs extension from commonOptions
|
||||||
|
outExtension: {},
|
||||||
}
|
}
|
||||||
skipOut = true;
|
skipOut = true;
|
||||||
skipOutTest = true;
|
skipOutTest = true;
|
||||||
@@ -171,7 +180,8 @@ if (config.addon) {
|
|||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`src/headless/public/Terminal.ts`],
|
entryPoints: [`src/headless/public/Terminal.ts`],
|
||||||
outfile: `headless/lib-headless/xterm-headless.mjs`
|
outdir: `headless/lib-headless`,
|
||||||
|
entryNames: 'xterm-headless',
|
||||||
};
|
};
|
||||||
outConfig = {
|
outConfig = {
|
||||||
...outConfig,
|
...outConfig,
|
||||||
@@ -183,7 +193,8 @@ if (config.addon) {
|
|||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`src/browser/public/Terminal.ts`],
|
entryPoints: [`src/browser/public/Terminal.ts`],
|
||||||
outfile: `lib/xterm.mjs`
|
outdir: `lib`,
|
||||||
|
entryNames: 'xterm',
|
||||||
};
|
};
|
||||||
outConfig = {
|
outConfig = {
|
||||||
...outConfig,
|
...outConfig,
|
||||||
|
|||||||
+1
-1
@@ -23,6 +23,6 @@
|
|||||||
<div id="sidebar" class="grid">
|
<div id="sidebar" class="grid">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="dist/client-bundle.js" defer ></script>
|
<script src="dist/client-bundle.mjs" type="module" defer ></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,6 @@
|
|||||||
</head>
|
</head>
|
||||||
<body id="test">
|
<body id="test">
|
||||||
<div id="terminal-container"></div>
|
<div id="terminal-container"></div>
|
||||||
<script src="/dist/client-bundle.js" defer></script>
|
<script src="/dist/client-bundle.mjs" type="module" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { OscLinkProvider } from 'browser/OscLinkProvider';
|
|||||||
import { CharacterJoinerHandler, CustomKeyEventHandler, CustomWheelEventHandler, IBrowser, IBufferRange, ICompositionHelper, ILinkifier2, ITerminal } from 'browser/Types';
|
import { CharacterJoinerHandler, CustomKeyEventHandler, CustomWheelEventHandler, IBrowser, IBufferRange, ICompositionHelper, ILinkifier2, ITerminal } from 'browser/Types';
|
||||||
import { Viewport } from 'browser/Viewport';
|
import { Viewport } from 'browser/Viewport';
|
||||||
import { BufferDecorationRenderer } from 'browser/decorations/BufferDecorationRenderer';
|
import { BufferDecorationRenderer } from 'browser/decorations/BufferDecorationRenderer';
|
||||||
import { OverviewRulerRenderer } from 'browser/decorations/OverviewRulerRenderer';
|
import type { OverviewRulerRenderer } from 'browser/decorations/OverviewRulerRenderer';
|
||||||
import { CompositionHelper } from 'browser/input/CompositionHelper';
|
import { CompositionHelper } from 'browser/input/CompositionHelper';
|
||||||
import { DomRenderer } from 'browser/renderer/dom/DomRenderer';
|
import { DomRenderer } from 'browser/renderer/dom/DomRenderer';
|
||||||
import { IRenderer } from 'browser/renderer/shared/Types';
|
import { IRenderer } from 'browser/renderer/shared/Types';
|
||||||
@@ -53,12 +53,34 @@ import { toRgbString } from 'common/input/XParseColor';
|
|||||||
import { DecorationService } from 'common/services/DecorationService';
|
import { DecorationService } from 'common/services/DecorationService';
|
||||||
import { IDecorationService } from 'common/services/Services';
|
import { IDecorationService } from 'common/services/Services';
|
||||||
import { WindowsOptionsReportType } from '../common/InputHandler';
|
import { WindowsOptionsReportType } from '../common/InputHandler';
|
||||||
import { AccessibilityManager } from './AccessibilityManager';
|
import type { AccessibilityManager } from './AccessibilityManager';
|
||||||
import { Linkifier } from './Linkifier';
|
import { Linkifier } from './Linkifier';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { addDisposableListener } from 'vs/base/browser/dom';
|
import { addDisposableListener } from 'vs/base/browser/dom';
|
||||||
import { MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily loaded AccessibilityManager module.
|
||||||
|
*/
|
||||||
|
let accessibilityManagerModule: Promise<typeof import('./AccessibilityManager')> | undefined;
|
||||||
|
function loadAccessibilityManager(): Promise<typeof import('./AccessibilityManager')> {
|
||||||
|
if (!accessibilityManagerModule) {
|
||||||
|
accessibilityManagerModule = import('./AccessibilityManager');
|
||||||
|
}
|
||||||
|
return accessibilityManagerModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily loaded OverviewRulerRenderer module.
|
||||||
|
*/
|
||||||
|
let overviewRulerRendererModule: Promise<typeof import('browser/decorations/OverviewRulerRenderer')> | undefined;
|
||||||
|
function loadOverviewRulerRenderer(): Promise<typeof import('browser/decorations/OverviewRulerRenderer')> {
|
||||||
|
if (!overviewRulerRendererModule) {
|
||||||
|
overviewRulerRendererModule = import('browser/decorations/OverviewRulerRenderer');
|
||||||
|
}
|
||||||
|
return overviewRulerRendererModule;
|
||||||
|
}
|
||||||
|
|
||||||
export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
||||||
public textarea: HTMLTextAreaElement | undefined;
|
public textarea: HTMLTextAreaElement | undefined;
|
||||||
public element: HTMLElement | undefined;
|
public element: HTMLElement | undefined;
|
||||||
@@ -277,7 +299,14 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|||||||
private _handleScreenReaderModeOptionChange(value: boolean): void {
|
private _handleScreenReaderModeOptionChange(value: boolean): void {
|
||||||
if (value) {
|
if (value) {
|
||||||
if (!this._accessibilityManager.value && this._renderService) {
|
if (!this._accessibilityManager.value && this._renderService) {
|
||||||
this._accessibilityManager.value = this._instantiationService.createInstance(AccessibilityManager, this);
|
loadAccessibilityManager().then(module => {
|
||||||
|
// Check again after async load in case option changed
|
||||||
|
if (this.options.screenReaderMode && !this._accessibilityManager.value && this._renderService) {
|
||||||
|
this._accessibilityManager.value = this._instantiationService.createInstance(module.AccessibilityManager, this);
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
// Failed to load accessibility manager module
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._accessibilityManager.clear();
|
this._accessibilityManager.clear();
|
||||||
@@ -588,16 +617,34 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|||||||
if (this.options.screenReaderMode) {
|
if (this.options.screenReaderMode) {
|
||||||
// Note that this must be done *after* the renderer is created in order to
|
// Note that this must be done *after* the renderer is created in order to
|
||||||
// ensure the correct order of the dprchange event
|
// ensure the correct order of the dprchange event
|
||||||
this._accessibilityManager.value = this._instantiationService.createInstance(AccessibilityManager, this);
|
loadAccessibilityManager().then(module => {
|
||||||
|
if (this.options.screenReaderMode && !this._accessibilityManager.value && this._renderService) {
|
||||||
|
this._accessibilityManager.value = this._instantiationService.createInstance(module.AccessibilityManager, this);
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
// Failed to load accessibility manager module
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this._register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e)));
|
this._register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e)));
|
||||||
|
|
||||||
if (this.options.overviewRuler.width) {
|
if (this.options.overviewRuler.width) {
|
||||||
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
loadOverviewRulerRenderer().then(module => {
|
||||||
|
if (this.options.overviewRuler.width && !this._overviewRulerRenderer && this._viewportElement && this.screenElement) {
|
||||||
|
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(module.OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
// Failed to load overview ruler renderer module
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.optionsService.onSpecificOptionChange('overviewRuler', value => {
|
this.optionsService.onSpecificOptionChange('overviewRuler', value => {
|
||||||
if (!this._overviewRulerRenderer && value && this._viewportElement && this.screenElement) {
|
if (!this._overviewRulerRenderer && value && this._viewportElement && this.screenElement) {
|
||||||
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
loadOverviewRulerRenderer().then(module => {
|
||||||
|
if (!this._overviewRulerRenderer && this.options.overviewRuler.width && this._viewportElement && this.screenElement) {
|
||||||
|
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(module.OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
// Failed to load overview ruler renderer module
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Measure the character size
|
// Measure the character size
|
||||||
|
|||||||
Reference in New Issue
Block a user