Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/vs/workbench/contrib/terminal/browser/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { EditorInput } from '../../../common/editor/editorInput.js';
import { IEditableData } from '../../../common/views.js';
import { ITerminalStatusList } from './terminalStatusList.js';
import { XtermTerminal } from './xterm/xtermTerminal.js';
import { IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfiguration, ITerminalFont, ITerminalProcessExtHostProxy, ITerminalProcessInfo } from '../common/terminal.js';
import { IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalFont, ITerminalProcessExtHostProxy, ITerminalProcessInfo } from '../common/terminal.js';
import type { IMarker, ITheme, Terminal as RawXtermTerminal, IBufferRange, IMarker as IXtermMarker } from '@xterm/xterm';
import { ScrollPosition } from './xterm/markNavigationAddon.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
Expand All @@ -33,6 +33,7 @@ import type { IMenu } from '../../../../platform/actions/common/actions.js';
import type { IProgressState } from '@xterm/addon-progress';
import type { IEditorOptions } from '../../../../platform/editor/common/editor.js';
import type { TerminalEditorInput } from './terminalEditorInput.js';
import type { ITerminalConfiguration2 } from '../common/terminalConfiguration.js';

export const ITerminalService = createDecorator<ITerminalService>('terminalService');
export const ITerminalConfigurationService = createDecorator<ITerminalConfigurationService>('terminalConfigurationService');
Expand Down Expand Up @@ -462,7 +463,7 @@ export interface ITerminalConfigurationService {
/**
* A typed and partially validated representation of the terminal configuration.
*/
readonly config: Readonly<ITerminalConfiguration>;
readonly config: ITerminalConfiguration2;

/**
* The default location for terminals.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import { EDITOR_FONT_DEFAULTS } from '../../../../editor/common/config/fontInfo.
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { ITerminalConfigurationService, LinuxDistro } from './terminal.js';
import type { IXtermCore } from './xterm-private.js';
import { DEFAULT_BOLD_FONT_WEIGHT, DEFAULT_FONT_WEIGHT, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, FontWeight, ITerminalConfiguration, MAXIMUM_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, MINIMUM_LETTER_SPACING, TERMINAL_CONFIG_SECTION, type ITerminalFont } from '../common/terminal.js';
import { DEFAULT_BOLD_FONT_WEIGHT, DEFAULT_FONT_WEIGHT, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, FontWeight, MAXIMUM_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, MINIMUM_LETTER_SPACING, TERMINAL_CONFIG_SECTION, type ITerminalFont } from '../common/terminal.js';
import { isMacintosh } from '../../../../base/common/platform.js';
import { TerminalLocation, TerminalLocationConfigValue } from '../../../../platform/terminal/common/terminal.js';
import type { ITerminalConfiguration2 } from '../common/terminalConfiguration.js';

// #region TerminalConfigurationService

Expand All @@ -21,7 +22,7 @@ export class TerminalConfigurationService extends Disposable implements ITermina

protected _fontMetrics: TerminalFontMetrics;

protected _config!: Readonly<ITerminalConfiguration>;
protected _config!: ITerminalConfiguration2;
get config() { return this._config; }

get defaultLocation(): TerminalLocation {
Expand Down Expand Up @@ -53,7 +54,7 @@ export class TerminalConfigurationService extends Disposable implements ITermina
getFont(w: Window, xtermCore?: IXtermCore, excludeDimensions?: boolean): ITerminalFont { return this._fontMetrics.getFont(w, xtermCore, excludeDimensions); }

private _updateConfig(): void {
const configValues = { ...this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION) };
const configValues = { ...this._configurationService.getValue<ITerminalConfiguration2>(TERMINAL_CONFIG_SECTION) };
configValues.fontWeight = this._normalizeFontWeight(configValues.fontWeight, DEFAULT_FONT_WEIGHT);
configValues.fontWeightBold = this._normalizeFontWeight(configValues.fontWeightBold, DEFAULT_BOLD_FONT_WEIGHT);
this._config = configValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this.xterm!.raw.options.screenReaderMode = this._accessibilityService.isScreenReaderOptimized();
}

private _setCommandsToSkipShell(commands: string[]): void {
private _setCommandsToSkipShell(commands: readonly string[]): void {
const excludeCommands = commands.filter(command => command[0] === '-').map(command => command.slice(1));
this._skipTerminalCommands = DEFAULT_COMMANDS_TO_SKIP_SHELL.filter(defaultCommand => {
return !excludeCommands.includes(defaultCommand);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
}
this._ligaturesAddon.value = this._instantiationService.createInstance(LigaturesAddon, {
fontFeatureSettings: ligaturesConfig.featureSettings,
fallbackLigatures: ligaturesConfig.fallbackLigatures,
fallbackLigatures: Array.from(ligaturesConfig.fallbackLigatures),
});
this.raw.loadAddon(this._ligaturesAddon.value);
shouldRecreateWebglRenderer = true;
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const MINIMUM_FONT_WEIGHT = 1;
export const MAXIMUM_FONT_WEIGHT = 1000;
export const DEFAULT_FONT_WEIGHT = 'normal';
export const DEFAULT_BOLD_FONT_WEIGHT = 'bold';
export const SUGGESTIONS_FONT_WEIGHT = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
export const SUGGESTIONS_FONT_WEIGHT: FontWeight[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];

export const ITerminalProfileResolverService = createDecorator<ITerminalProfileResolverService>('terminalProfileResolverService');
export interface ITerminalProfileResolverService {
Expand Down Expand Up @@ -96,7 +96,7 @@ export interface IShellLaunchConfigResolveOptions {
allowAutomationShell?: boolean;
}

export type FontWeight = 'normal' | 'bold' | number;
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number;

export interface ITerminalProfiles {
linux: { [key: string]: ITerminalProfileObject };
Expand Down
115 changes: 96 additions & 19 deletions src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

import { Codicon } from '../../../../base/common/codicons.js';
import type { IStringDictionary } from '../../../../base/common/collections.js';
import { IJSONSchemaSnippet } from '../../../../base/common/jsonSchema.js';
import { IJSONSchemaSnippet, type TypeFromJsonSchema } from '../../../../base/common/jsonSchema.js';
import { isMacintosh, isWindows } from '../../../../base/common/platform.js';
import { localize } from '../../../../nls.js';
import { ConfigurationScope, Extensions, IConfigurationRegistry, type IConfigurationPropertySchema } from '../../../../platform/configuration/common/configurationRegistry.js';
import product from '../../../../platform/product/common/product.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { TerminalLocationConfigValue, TerminalSettingId } from '../../../../platform/terminal/common/terminal.js';
import { TerminalLocationConfigValue, TerminalSettingId, type ITerminalProfileObject } from '../../../../platform/terminal/common/terminal.js';
import { terminalColorSchema, terminalIconSchema } from '../../../../platform/terminal/common/terminalPlatformConfiguration.js';
import { ConfigurationKeyValuePairs, IConfigurationMigrationRegistry, Extensions as WorkbenchExtensions } from '../../../common/configuration.js';
import { terminalContribConfiguration, TerminalContribSettingId } from '../terminalContribExports.js';
import { DEFAULT_COMMANDS_TO_SKIP_SHELL, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MAXIMUM_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, SUGGESTIONS_FONT_WEIGHT } from './terminal.js';
import { DEFAULT_COMMANDS_TO_SKIP_SHELL, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MAXIMUM_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, SUGGESTIONS_FONT_WEIGHT, type FontWeight, type ITerminalProfiles } from './terminal.js';

const terminalDescriptors = '\n- ' + [
'`\${cwd}`: ' + localize("cwd", "the terminal's current working directory."),
Expand All @@ -41,7 +41,7 @@ terminalDescription += terminalDescriptors;

export const defaultTerminalFontSize = isMacintosh ? 12 : 14;

const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
const terminalConfigurationConst = {
[TerminalSettingId.SendKeybindingsToShell]: {
markdownDescription: localize('terminal.integrated.sendKeybindingsToShell', "Dispatches most keybindings to the terminal instead of the workbench, overriding {0}, which can be used alternatively for fine tuning.", '`#terminal.integrated.commandsToSkipShell#`'),
type: 'boolean',
Expand Down Expand Up @@ -190,7 +190,7 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
[TerminalSettingId.FontLigaturesFallbackLigatures]: {
markdownDescription: localize('terminal.integrated.fontLigatures.fallbackLigatures', "When {0} is enabled and the particular {1} cannot be parsed, this is the set of character sequences that will always be drawn together. This allows the use of a fixed set of ligatures even when the font isn't supported.", `\`#${TerminalSettingId.GpuAcceleration}#\``, `\`#${TerminalSettingId.FontFamily}#\``),
type: 'array',
items: [{ type: 'string' }],
items: { type: 'string' },
default: [
'<--', '<---', '<<-', '<-', '->', '->>', '-->', '--->',
'<==', '<===', '<<=', '<=', '=>', '=>>', '==>', '===>', '>=', '>>=',
Expand Down Expand Up @@ -254,11 +254,9 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
},
{
type: 'string',
pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'
},
{
pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$',
enum: SUGGESTIONS_FONT_WEIGHT,
}
},
],
description: localize('terminal.integrated.fontWeight', "The font weight to use within the terminal for non-bold text. Accepts \"normal\" and \"bold\" keywords or numbers between 1 and 1000."),
default: 'normal'
Expand All @@ -273,11 +271,9 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
},
{
type: 'string',
pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'
},
{
pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$',
enum: SUGGESTIONS_FONT_WEIGHT,
}
},
],
description: localize('terminal.integrated.fontWeightBold', "The font weight to use within the terminal for bold text. Accepts \"normal\" and \"bold\" keywords or numbers between 1 and 1000."),
default: 'bold'
Expand Down Expand Up @@ -416,9 +412,7 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {

),
type: 'array',
items: {
type: 'string'
},
items: { type: 'string' },
default: []
},
[TerminalSettingId.AllowChords]: {
Expand Down Expand Up @@ -510,9 +504,7 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
[TerminalSettingId.AllowedLinkSchemes]: {
description: localize('terminal.integrated.allowedLinkSchemes', "An array of strings containing the URI schemes that the terminal is allowed to open links for. By default, only a small subset of possible schemes are allowed for security reasons."),
type: 'array',
items: {
type: 'string'
},
items: { type: 'string' },
default: [
'file',
'http',
Expand Down Expand Up @@ -660,8 +652,93 @@ const terminalConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
tags: ['advanced']
},
...terminalContribConfiguration,
} as const satisfies IStringDictionary<IConfigurationPropertySchema>;

const terminalConfiguration = terminalConfigurationConst as IStringDictionary<IConfigurationPropertySchema>;

// Helper type to make string arrays readonly
type MakeArraysReadonly<T> = T extends string[] ? readonly string[] : T;

// Helpers to convert dot notation keys to nested objects
type SplitKey<K extends string> = K extends `${infer First}.${infer Rest}` ? [First, Rest] : [K, never];

// Get all first parts of dot notation keys
type FirstParts<T> = {
[K in keyof T]: SplitKey<K & string>[0]
}[keyof T];

// Get all keys that start with a specific prefix
type KeysStartingWith<T, Prefix extends string> = {
[K in keyof T]: K extends `${Prefix}.${string}` ? K : never
}[keyof T];

// Get all keys that exactly match (no dots)
type ExactKeys<T> = {
[K in keyof T]: K extends `${string}.${string}` ? never : K
}[keyof T];

// Build nested object by grouping keys
type NestedObject<T> = {
// Exact matches (no dots)
readonly [K in ExactKeys<T>]: MakeArraysReadonly<T[K]>
} & {
// Nested objects
readonly [P in FirstParts<T> as P extends ExactKeys<T> ? never : P]: NestedObject<{
[K in KeysStartingWith<T, P> as K extends `${P}.${infer Rest}` ? Rest : never]: T[K]
}>
};

// Assemble config interface with flat keys, excluding terminal.integrated.
type FlatTerminalConfig = (
Omit<{
[K in keyof typeof terminalConfigurationConst as K extends `terminal.integrated.${infer Rest}` ? Rest : K]: TypeFromJsonSchema<typeof terminalConfigurationConst[K]>
}, (
// Omit keys that resolve to never
'env.linux' |
'env.osx' |
'env.windows' |
'tabs.defaultColor' |
'tabs.defaultIcon' |
// Omit keys that don't pull correct type
'fontWeight' |
'fontWeightBold'
)
>
&
{
// Manually set keys that don't resolve correctly
'env.linux': { [key: string]: string | null };
'env.osx': { [key: string]: string | null };
'env.windows': { [key: string]: string | null };
'tabs.defaultColor': null | 'terminal.ansiBlack' | 'terminal.ansiRed' | 'terminal.ansiGreen' | 'terminal.ansiYellow' | 'terminal.ansiBlue' | 'terminal.ansiMagenta' | 'terminal.ansiCyan' | 'terminal.ansiWhite';
'tabs.defaultIcon': string;
'fontWeight': FontWeight | number;
'fontWeightBold': FontWeight | number;
// Manually set keys that come from platform configuration
// TODO: Derive these from JSON
// TODO: Not all platform configs are included here
automationShell: {
linux: string | null;
osx: string | null;
windows: string | null;
};
profiles: {
linux: { [key: string]: ITerminalProfileObject };
osx: { [key: string]: ITerminalProfileObject };
windows: { [key: string]: ITerminalProfileObject };
};
defaultProfile: {
linux: string | null;
osx: string | null;
windows: string | null;
};
useWslProfiles: boolean;
}
);

// Map flat keys to nested object
export type ITerminalConfiguration2 = NestedObject<FlatTerminalConfig>;

export async function registerTerminalConfiguration(getFontSnippets: () => Promise<IJSONSchemaSnippet[]>) {
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
configurationRegistry.registerConfiguration({
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/test/browser/workbenchTestServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ import { TerminalConfigurationService } from '../../contrib/terminal/browser/ter
import { TerminalEditorInput } from '../../contrib/terminal/browser/terminalEditorInput.js';
import { IEnvironmentVariableService } from '../../contrib/terminal/common/environmentVariable.js';
import { EnvironmentVariableService } from '../../contrib/terminal/common/environmentVariableService.js';
import { IRegisterContributedProfileArgs, IShellLaunchConfigResolveOptions, ITerminalProfileProvider, ITerminalProfileResolverService, ITerminalProfileService, type ITerminalConfiguration } from '../../contrib/terminal/common/terminal.js';
import { IRegisterContributedProfileArgs, IShellLaunchConfigResolveOptions, ITerminalProfileProvider, ITerminalProfileResolverService, ITerminalProfileService } from '../../contrib/terminal/common/terminal.js';
import { IChatEntitlementService } from '../../services/chat/common/chatEntitlementService.js';
import { IDecoration, IDecorationData, IDecorationsProvider, IDecorationsService, IResourceDecorationChangeEvent } from '../../services/decorations/common/decorations.js';
import { CodeEditorService } from '../../services/editor/browser/codeEditorService.js';
Expand Down Expand Up @@ -186,6 +186,7 @@ import { IWorkingCopyEditorService, WorkingCopyEditorService } from '../../servi
import { IWorkingCopyFileService, WorkingCopyFileService } from '../../services/workingCopy/common/workingCopyFileService.js';
import { IWorkingCopyService, WorkingCopyService } from '../../services/workingCopy/common/workingCopyService.js';
import { TestChatEntitlementService, TestContextService, TestExtensionService, TestFileService, TestHistoryService, TestLoggerService, TestMarkerService, TestProductService, TestStorageService, TestTextResourcePropertiesService, TestWorkspaceTrustManagementService, TestWorkspaceTrustRequestService } from '../common/workbenchTestServices.js';
import type { ITerminalConfiguration2 } from '../../contrib/terminal/common/terminalConfiguration.js';

// Backcompat export
export { TestFileService };
Expand Down Expand Up @@ -1966,7 +1967,7 @@ export class TestTerminalProfileResolverService implements ITerminalProfileResol
export class TestTerminalConfigurationService extends TerminalConfigurationService {
get fontMetrics() { return this._fontMetrics; }
// eslint-disable-next-line local/code-no-any-casts
setConfig(config: Partial<ITerminalConfiguration>) { this._config = config as any; }
setConfig(config: Partial<ITerminalConfiguration2>) { this._config = config as any; }
}

export class TestQuickInputService implements IQuickInputService {
Expand Down
Loading