chore(vscode): update to 1.56.0
This commit is contained in:
2
lib/vscode/src/bootstrap-node.js
vendored
2
lib/vscode/src/bootstrap-node.js
vendored
@ -98,7 +98,7 @@ exports.removeGlobalNodeModuleLookupPaths = function () {
|
||||
/**
|
||||
* Helper to enable portable mode.
|
||||
*
|
||||
* @param {Partial<import('./vs/platform/product/common/productService').IProductConfiguration>} product
|
||||
* @param {Partial<import('./vs/base/common/product').IProductConfiguration>} product
|
||||
* @returns {{ portableDataPath: string; isPortable: boolean; }}
|
||||
*/
|
||||
exports.configurePortable = function (product) {
|
||||
|
139
lib/vscode/src/bootstrap-window.js
vendored
139
lib/vscode/src/bootstrap-window.js
vendored
@ -22,45 +22,65 @@
|
||||
}
|
||||
}(this, function () {
|
||||
const bootstrapLib = bootstrap();
|
||||
const preloadGlobals = globals();
|
||||
const webFrame = preloadGlobals.webFrame;
|
||||
const preloadGlobals = sandboxGlobals();
|
||||
const safeProcess = preloadGlobals.process;
|
||||
const configuration = parseWindowConfiguration();
|
||||
const useCustomProtocol = safeProcess.sandboxed || typeof safeProcess.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] === 'string';
|
||||
|
||||
// Start to resolve process.env before anything gets load
|
||||
// so that we can run loading and resolving in parallel
|
||||
const whenEnvResolved = safeProcess.resolveEnv(configuration.userEnv);
|
||||
const useCustomProtocol = safeProcess.sandboxed || typeof safeProcess.env['VSCODE_BROWSER_CODE_LOADING'] === 'string';
|
||||
|
||||
/**
|
||||
* @typedef {import('./vs/base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
*
|
||||
* @param {string[]} modulePaths
|
||||
* @param {(result: unknown, configuration: object) => Promise<unknown> | undefined} resultCallback
|
||||
* @param {{ forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options
|
||||
* @param {(result: unknown, configuration: ISandboxConfiguration) => Promise<unknown> | undefined} resultCallback
|
||||
* @param {{
|
||||
* configureDeveloperSettings?: (config: ISandboxConfiguration) => {
|
||||
* forceDisableShowDevtoolsOnError?: boolean,
|
||||
* forceEnableDeveloperKeybindings?: boolean,
|
||||
* disallowReloadKeybinding?: boolean,
|
||||
* removeDeveloperKeybindingsAfterLoad?: boolean
|
||||
* },
|
||||
* canModifyDOM?: (config: ISandboxConfiguration) => void,
|
||||
* beforeLoaderConfig?: (loaderConfig: object) => void,
|
||||
* beforeRequire?: () => void
|
||||
* }} [options]
|
||||
*/
|
||||
function load(modulePaths, resultCallback, options) {
|
||||
async function load(modulePaths, resultCallback, options) {
|
||||
|
||||
// Apply zoom level early to avoid glitches
|
||||
const zoomLevel = configuration.zoomLevel;
|
||||
if (typeof zoomLevel === 'number' && zoomLevel !== 0) {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
}
|
||||
|
||||
// Error handler
|
||||
safeProcess.on('uncaughtException', function (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
// Error handler (TODO@sandbox non-sandboxed only)
|
||||
let showDevtoolsOnError = !!safeProcess.env['VSCODE_DEV'];
|
||||
safeProcess.on('uncaughtException', function (/** @type {string | Error} */ error) {
|
||||
onUnexpectedError(error, showDevtoolsOnError);
|
||||
});
|
||||
|
||||
// Developer tools
|
||||
const enableDeveloperTools = (safeProcess.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath;
|
||||
let developerToolsUnbind;
|
||||
if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) {
|
||||
developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding);
|
||||
// Await window configuration from preload
|
||||
performance.mark('code/willWaitForWindowConfig');
|
||||
/** @type {ISandboxConfiguration} */
|
||||
const configuration = await preloadGlobals.context.resolveConfiguration();
|
||||
performance.mark('code/didWaitForWindowConfig');
|
||||
|
||||
// Developer settings
|
||||
const {
|
||||
forceDisableShowDevtoolsOnError,
|
||||
forceEnableDeveloperKeybindings,
|
||||
disallowReloadKeybinding,
|
||||
removeDeveloperKeybindingsAfterLoad
|
||||
} = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : {
|
||||
forceDisableShowDevtoolsOnError: false,
|
||||
forceEnableDeveloperKeybindings: false,
|
||||
disallowReloadKeybinding: false,
|
||||
removeDeveloperKeybindingsAfterLoad: false
|
||||
};
|
||||
showDevtoolsOnError = safeProcess.env['VSCODE_DEV'] && !forceDisableShowDevtoolsOnError;
|
||||
const enableDeveloperKeybindings = safeProcess.env['VSCODE_DEV'] || forceEnableDeveloperKeybindings;
|
||||
let developerDeveloperKeybindingsDisposable;
|
||||
if (enableDeveloperKeybindings) {
|
||||
developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);
|
||||
}
|
||||
|
||||
// Enable ASAR support
|
||||
globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot);
|
||||
|
||||
if (options && typeof options.canModifyDOM === 'function') {
|
||||
// Signal DOM modifications are now OK
|
||||
if (typeof options?.canModifyDOM === 'function') {
|
||||
options.canModifyDOM(configuration);
|
||||
}
|
||||
|
||||
@ -76,24 +96,22 @@
|
||||
|
||||
window.document.documentElement.setAttribute('lang', locale);
|
||||
|
||||
// do not advertise AMD to avoid confusing UMD modules loaded with nodejs
|
||||
// Do not advertise AMD to avoid confusing UMD modules loaded with nodejs
|
||||
if (!useCustomProtocol) {
|
||||
window['define'] = undefined;
|
||||
}
|
||||
|
||||
// replace the patched electron fs with the original node fs for all AMD code (TODO@sandbox non-sandboxed only)
|
||||
// Replace the patched electron fs with the original node fs for all AMD code (TODO@sandbox non-sandboxed only)
|
||||
if (!safeProcess.sandboxed) {
|
||||
require.define('fs', [], function () { return require.__$__nodeRequire('original-fs'); });
|
||||
}
|
||||
|
||||
window['MonacoEnvironment'] = {};
|
||||
|
||||
const baseUrl = useCustomProtocol ?
|
||||
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out` :
|
||||
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32' })}/out`;
|
||||
|
||||
const loaderConfig = {
|
||||
baseUrl,
|
||||
baseUrl: useCustomProtocol ?
|
||||
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out` :
|
||||
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32' })}/out`,
|
||||
'vs/nls': nlsConfig,
|
||||
preferScriptTags: useCustomProtocol
|
||||
};
|
||||
@ -129,7 +147,7 @@
|
||||
loaderConfig.amdModulesPattern = /^vs\//;
|
||||
}
|
||||
|
||||
// cached data config
|
||||
// Cached data config
|
||||
if (configuration.nodeCachedDataDir) {
|
||||
loaderConfig.nodeCachedData = {
|
||||
path: configuration.nodeCachedDataDir,
|
||||
@ -137,29 +155,34 @@
|
||||
};
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeLoaderConfig === 'function') {
|
||||
options.beforeLoaderConfig(configuration, loaderConfig);
|
||||
// Signal before require.config()
|
||||
if (typeof options?.beforeLoaderConfig === 'function') {
|
||||
options.beforeLoaderConfig(loaderConfig);
|
||||
}
|
||||
|
||||
// Configure loader
|
||||
require.config(loaderConfig);
|
||||
|
||||
// Handle pseudo NLS
|
||||
if (nlsConfig.pseudo) {
|
||||
require(['vs/nls'], function (nlsPlugin) {
|
||||
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
|
||||
});
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeRequire === 'function') {
|
||||
// Signal before require()
|
||||
if (typeof options?.beforeRequire === 'function') {
|
||||
options.beforeRequire();
|
||||
}
|
||||
|
||||
// Actually require the main module as specified
|
||||
require(modulePaths, async result => {
|
||||
try {
|
||||
|
||||
// Wait for process environment being fully resolved
|
||||
performance.mark('code/willWaitForShellEnv');
|
||||
if (!safeProcess.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) {
|
||||
await whenEnvResolved;
|
||||
await safeProcess.shellEnv();
|
||||
}
|
||||
performance.mark('code/didWaitForShellEnv');
|
||||
|
||||
@ -168,39 +191,16 @@
|
||||
if (callbackResult instanceof Promise) {
|
||||
await callbackResult;
|
||||
|
||||
if (developerToolsUnbind && options && options.removeDeveloperKeybindingsAfterLoad) {
|
||||
developerToolsUnbind();
|
||||
if (developerDeveloperKeybindingsDisposable && removeDeveloperKeybindingsAfterLoad) {
|
||||
developerDeveloperKeybindingsDisposable();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
onUnexpectedError(error, enableDeveloperKeybindings);
|
||||
}
|
||||
}, onUnexpectedError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the contents of the window condiguration that
|
||||
* is passed into the URL from the `electron-main` side.
|
||||
*
|
||||
* @returns {{
|
||||
* zoomLevel?: number,
|
||||
* extensionDevelopmentPath?: string[],
|
||||
* extensionTestsPath?: string,
|
||||
* userEnv?: { [key: string]: string | undefined },
|
||||
* appRoot: string,
|
||||
* nodeCachedDataDir?: string
|
||||
* }}
|
||||
*/
|
||||
function parseWindowConfiguration() {
|
||||
const rawConfiguration = (window.location.search || '').split(/[?&]/)
|
||||
.filter(function (param) { return !!param; })
|
||||
.map(function (param) { return param.split('='); })
|
||||
.filter(function (param) { return param.length === 2; })
|
||||
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
|
||||
|
||||
return JSON.parse(rawConfiguration['config'] || '{}') || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean | undefined} disallowReloadKeybinding
|
||||
* @returns {() => void}
|
||||
@ -249,10 +249,10 @@
|
||||
|
||||
/**
|
||||
* @param {string | Error} error
|
||||
* @param {boolean} [enableDeveloperTools]
|
||||
* @param {boolean} [showDevtoolsOnError]
|
||||
*/
|
||||
function onUnexpectedError(error, enableDeveloperTools) {
|
||||
if (enableDeveloperTools) {
|
||||
function onUnexpectedError(error, showDevtoolsOnError) {
|
||||
if (showDevtoolsOnError) {
|
||||
const ipcRenderer = preloadGlobals.ipcRenderer;
|
||||
ipcRenderer.send('vscode:openDevTools');
|
||||
}
|
||||
@ -275,13 +275,12 @@
|
||||
/**
|
||||
* @return {typeof import('./vs/base/parts/sandbox/electron-sandbox/globals')}
|
||||
*/
|
||||
function globals() {
|
||||
function sandboxGlobals() {
|
||||
// @ts-ignore (defined in globals.js)
|
||||
return window.vscode;
|
||||
}
|
||||
|
||||
return {
|
||||
load,
|
||||
globals
|
||||
load
|
||||
};
|
||||
}));
|
||||
|
18
lib/vscode/src/bootstrap.js
vendored
18
lib/vscode/src/bootstrap.js
vendored
@ -173,7 +173,7 @@
|
||||
/**
|
||||
* @returns {typeof import('./vs/base/parts/sandbox/electron-sandbox/globals') | undefined}
|
||||
*/
|
||||
function safeGlobals() {
|
||||
function safeSandboxGlobals() {
|
||||
const globals = (typeof self === 'object' ? self : typeof global === 'object' ? global : {});
|
||||
|
||||
return globals.vscode;
|
||||
@ -183,13 +183,13 @@
|
||||
* @returns {import('./vs/base/parts/sandbox/electron-sandbox/globals').ISandboxNodeProcess | NodeJS.Process}
|
||||
*/
|
||||
function safeProcess() {
|
||||
if (typeof process !== 'undefined') {
|
||||
return process; // Native environment (non-sandboxed)
|
||||
const sandboxGlobals = safeSandboxGlobals();
|
||||
if (sandboxGlobals) {
|
||||
return sandboxGlobals.process; // Native environment (sandboxed)
|
||||
}
|
||||
|
||||
const globals = safeGlobals();
|
||||
if (globals) {
|
||||
return globals.process; // Native environment (sandboxed)
|
||||
if (typeof process !== 'undefined') {
|
||||
return process; // Native environment (non-sandboxed)
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -199,9 +199,9 @@
|
||||
* @returns {import('./vs/base/parts/sandbox/electron-sandbox/electronTypes').IpcRenderer | undefined}
|
||||
*/
|
||||
function safeIpcRenderer() {
|
||||
const globals = safeGlobals();
|
||||
if (globals) {
|
||||
return globals.ipcRenderer;
|
||||
const sandboxGlobals = safeSandboxGlobals();
|
||||
if (sandboxGlobals) {
|
||||
return sandboxGlobals.ipcRenderer;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -19,5 +19,8 @@ bootstrapNode.configurePortable(product);
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport(undefined);
|
||||
|
||||
// Signal processes that we got launched as CLI
|
||||
process.env['VSCODE_CLI'] = '1';
|
||||
|
||||
// Load CLI through AMD loader
|
||||
require('./bootstrap-amd').load('vs/code/node/cli');
|
||||
|
@ -6,17 +6,22 @@
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @typedef {import('./vs/base/common/product').IProductConfiguration} IProductConfiguration
|
||||
* @typedef {import('./vs/base/node/languagePacks').NLSConfiguration} NLSConfiguration
|
||||
* @typedef {import('./vs/platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs
|
||||
*/
|
||||
|
||||
const perf = require('./vs/base/common/performance');
|
||||
perf.mark('code/didStartMain');
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const { getNLSConfiguration } = require('./vs/base/node/languagePacks');
|
||||
const bootstrap = require('./bootstrap');
|
||||
const bootstrapNode = require('./bootstrap-node');
|
||||
const { getUserDataPath } = require('./vs/platform/environment/node/userDataPath');
|
||||
/** @type {Partial<import('./vs/platform/product/common/productService').IProductConfiguration>} */
|
||||
/** @type {Partial<IProductConfiguration>} */
|
||||
const product = require('../product.json');
|
||||
const { app, protocol, crashReporter } = require('electron');
|
||||
|
||||
@ -39,7 +44,9 @@ app.setPath('userData', userDataPath);
|
||||
const argvConfig = configureCommandlineSwitchesSync(args);
|
||||
|
||||
// Configure crash reporter
|
||||
perf.mark('code/willStartCrashReporter');
|
||||
configureCrashReporter();
|
||||
perf.mark('code/didStartCrashReporter');
|
||||
|
||||
// Set logs path before app 'ready' event if running portable
|
||||
// to ensure that no 'logs' folder is created on disk at a
|
||||
@ -53,10 +60,7 @@ if (portable && portable.isPortable) {
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme: 'vscode-webview',
|
||||
privileges: { standard: true, secure: true, supportFetchAPI: true, corsEnabled: true }
|
||||
}, {
|
||||
scheme: 'vscode-webview-resource',
|
||||
privileges: { secure: true, standard: true, supportFetchAPI: true, corsEnabled: true }
|
||||
privileges: { standard: true, secure: true, supportFetchAPI: true, corsEnabled: true, allowServiceWorkers: true, }
|
||||
},
|
||||
{
|
||||
scheme: 'vscode-file',
|
||||
@ -74,13 +78,14 @@ const nodeCachedDataDir = getNodeCachedDir();
|
||||
* Support user defined locale: load it early before app('ready')
|
||||
* to have more things running in parallel.
|
||||
*
|
||||
* @type {Promise<import('./vs/base/node/languagePacks').NLSConfiguration> | undefined}
|
||||
* @type {Promise<NLSConfiguration> | undefined}
|
||||
*/
|
||||
let nlsConfigurationPromise = undefined;
|
||||
|
||||
const metaDataFile = path.join(__dirname, 'nls.metadata.json');
|
||||
const locale = getUserDefinedLocale(argvConfig);
|
||||
if (locale) {
|
||||
const { getNLSConfiguration } = require('./vs/base/node/languagePacks');
|
||||
nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
|
||||
}
|
||||
|
||||
@ -104,7 +109,7 @@ app.once('ready', function () {
|
||||
* Main startup routine
|
||||
*
|
||||
* @param {string | undefined} cachedDataDir
|
||||
* @param {import('./vs/base/node/languagePacks').NLSConfiguration} nlsConfig
|
||||
* @param {NLSConfiguration} nlsConfig
|
||||
*/
|
||||
function startup(cachedDataDir, nlsConfig) {
|
||||
nlsConfig._languagePackSupport = true;
|
||||
@ -132,7 +137,7 @@ async function onReady() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./vs/platform/environment/common/argv').NativeParsedArgs} cliArgs
|
||||
* @param {NativeParsedArgs} cliArgs
|
||||
*/
|
||||
function configureCommandlineSwitchesSync(cliArgs) {
|
||||
const SUPPORTED_ELECTRON_SWITCHES = [
|
||||
@ -159,16 +164,18 @@ function configureCommandlineSwitchesSync(cliArgs) {
|
||||
'enable-proposed-api',
|
||||
|
||||
// TODO@sandbox remove me once testing is done on `vscode-file` protocol
|
||||
// (all traces of `enable-browser-code-loading` and `ENABLE_VSCODE_BROWSER_CODE_LOADING`)
|
||||
// (all traces of `enable-browser-code-loading` and `VSCODE_BROWSER_CODE_LOADING`)
|
||||
'enable-browser-code-loading',
|
||||
|
||||
// Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.
|
||||
'log-level',
|
||||
'log-level'
|
||||
];
|
||||
|
||||
// Read argv config
|
||||
const argvConfig = readArgvConfigSync();
|
||||
|
||||
let browserCodeLoadingStrategy = undefined;
|
||||
|
||||
Object.keys(argvConfig).forEach(argvKey => {
|
||||
const argvValue = argvConfig[argvKey];
|
||||
|
||||
@ -204,8 +211,10 @@ function configureCommandlineSwitchesSync(cliArgs) {
|
||||
break;
|
||||
|
||||
case 'enable-browser-code-loading':
|
||||
if (typeof argvValue === 'string') {
|
||||
process.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] = argvValue;
|
||||
if (argvValue === false) {
|
||||
browserCodeLoadingStrategy = undefined;
|
||||
} else if (typeof argvValue === 'string') {
|
||||
browserCodeLoadingStrategy = argvValue;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -224,9 +233,9 @@ function configureCommandlineSwitchesSync(cliArgs) {
|
||||
app.commandLine.appendSwitch('js-flags', jsFlags);
|
||||
}
|
||||
|
||||
// Support __sandbox flag
|
||||
if (cliArgs.__sandbox) {
|
||||
process.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] = 'bypassHeatCheck';
|
||||
// Configure vscode-file:// code loading environment
|
||||
if (cliArgs.__sandbox || browserCodeLoadingStrategy) {
|
||||
process.env['VSCODE_BROWSER_CODE_LOADING'] = browserCodeLoadingStrategy || 'bypassHeatCheck';
|
||||
}
|
||||
|
||||
return argvConfig;
|
||||
@ -411,7 +420,7 @@ function configureCrashReporter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./vs/platform/environment/common/argv').NativeParsedArgs} cliArgs
|
||||
* @param {NativeParsedArgs} cliArgs
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getJSFlags(cliArgs) {
|
||||
@ -431,7 +440,7 @@ function getJSFlags(cliArgs) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('./vs/platform/environment/common/argv').NativeParsedArgs}
|
||||
* @returns {NativeParsedArgs}
|
||||
*/
|
||||
function parseCLIArgs() {
|
||||
const minimist = require('minimist');
|
||||
@ -549,7 +558,7 @@ function mkdirp(dir) {
|
||||
/**
|
||||
* Resolve the NLS configuration
|
||||
*
|
||||
* @return {Promise<import('./vs/base/node/languagePacks').NLSConfiguration>}
|
||||
* @return {Promise<NLSConfiguration>}
|
||||
*/
|
||||
async function resolveNlsConfiguration() {
|
||||
|
||||
@ -569,6 +578,7 @@ async function resolveNlsConfiguration() {
|
||||
// See above the comment about the loader and case sensitiviness
|
||||
appLocale = appLocale.toLowerCase();
|
||||
|
||||
const { getNLSConfiguration } = require('./vs/base/node/languagePacks');
|
||||
nlsConfiguration = await getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale);
|
||||
if (!nlsConfiguration) {
|
||||
nlsConfiguration = { locale: appLocale, availableLanguages: {} };
|
||||
|
@ -4,6 +4,7 @@
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitOverride": true,
|
||||
"noUnusedLocals": true,
|
||||
"allowUnreachableCode": false,
|
||||
"strict": true,
|
||||
|
@ -12,7 +12,8 @@
|
||||
"semver",
|
||||
"sinon",
|
||||
"winreg",
|
||||
"trusted-types"
|
||||
"trusted-types",
|
||||
"wicg-file-system-access"
|
||||
],
|
||||
"plugins": [
|
||||
{
|
||||
|
@ -2,9 +2,7 @@
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"types": [
|
||||
"trusted-types"
|
||||
],
|
||||
"types": ["trusted-types"],
|
||||
"paths": {},
|
||||
"module": "amd",
|
||||
"moduleResolution": "classic",
|
||||
@ -27,6 +25,7 @@
|
||||
"vs/platform/*/browser/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules/*"
|
||||
"node_modules/*",
|
||||
"vs/platform/files/browser/htmlFileSystemProvider.ts"
|
||||
]
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ export interface IContextMenuDelegate {
|
||||
getActions(): readonly IAction[];
|
||||
getCheckedActionsRepresentation?(action: IAction): 'radio' | 'checkbox';
|
||||
getActionViewItem?(action: IAction): IActionViewItem | undefined;
|
||||
getActionsContext?(event?: IContextMenuEvent): any;
|
||||
getActionsContext?(event?: IContextMenuEvent): unknown;
|
||||
getKeyBinding?(action: IAction): ResolvedKeybinding | undefined;
|
||||
getMenuClassName?(): string;
|
||||
onHide?(didCancel: boolean): void;
|
||||
|
@ -42,7 +42,7 @@ export class DelayedDragHandler extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.clearDragTimeout();
|
||||
@ -89,7 +89,7 @@ export function applyDragImage(event: DragEvent, label: string | null, clazz: st
|
||||
|
||||
export interface IDragAndDropData {
|
||||
update(dataTransfer: DataTransfer): void;
|
||||
getData(): any;
|
||||
getData(): unknown;
|
||||
}
|
||||
|
||||
export class DragAndDropData<T> implements IDragAndDropData {
|
||||
|
@ -1193,18 +1193,21 @@ export function computeScreenAwareSize(cssPx: number): number {
|
||||
* to change the location of the current page.
|
||||
* See https://mathiasbynens.github.io/rel-noopener/
|
||||
*/
|
||||
export function windowOpenNoOpener(url: string): void {
|
||||
export function windowOpenNoOpener(url: string): boolean {
|
||||
if (browser.isElectron || browser.isEdgeLegacyWebView) {
|
||||
// In VSCode, window.open() always returns null...
|
||||
// The same is true for a WebView (see https://github.com/microsoft/monaco-editor/issues/628)
|
||||
// Also call directly window.open in sandboxed Electron (see https://github.com/microsoft/monaco-editor/issues/2220)
|
||||
window.open(url);
|
||||
return true;
|
||||
} else {
|
||||
let newTab = window.open();
|
||||
if (newTab) {
|
||||
(newTab as any).opener = null;
|
||||
newTab.location.href = url;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1409,37 +1412,8 @@ export function multibyteAwareBtoa(str: string): string {
|
||||
*/
|
||||
export namespace WebFileSystemAccess {
|
||||
|
||||
// https://wicg.github.io/file-system-access/#dom-window-showdirectorypicker
|
||||
export interface FileSystemAccess {
|
||||
showDirectoryPicker: () => Promise<FileSystemDirectoryHandle>;
|
||||
}
|
||||
|
||||
// https://wicg.github.io/file-system-access/#api-filesystemdirectoryhandle
|
||||
export interface FileSystemDirectoryHandle {
|
||||
readonly kind: 'directory',
|
||||
readonly name: string,
|
||||
|
||||
getFileHandle: (name: string, options?: { create?: boolean }) => Promise<FileSystemFileHandle>;
|
||||
getDirectoryHandle: (name: string, options?: { create?: boolean }) => Promise<FileSystemDirectoryHandle>;
|
||||
}
|
||||
|
||||
// https://wicg.github.io/file-system-access/#api-filesystemfilehandle
|
||||
export interface FileSystemFileHandle {
|
||||
readonly kind: 'file',
|
||||
readonly name: string,
|
||||
|
||||
createWritable: (options?: { keepExistingData?: boolean }) => Promise<FileSystemWritableFileStream>;
|
||||
}
|
||||
|
||||
// https://wicg.github.io/file-system-access/#api-filesystemwritablefilestream
|
||||
export interface FileSystemWritableFileStream {
|
||||
write: (buffer: Uint8Array) => Promise<void>;
|
||||
close: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function supported(obj: any & Window): obj is FileSystemAccess {
|
||||
const candidate = obj as FileSystemAccess | undefined;
|
||||
if (typeof candidate?.showDirectoryPicker === 'function') {
|
||||
export function supported(obj: any & Window): boolean {
|
||||
if (typeof obj?.showDirectoryPicker === 'function') {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1589,7 +1563,7 @@ export class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
|
||||
return ModifierKeyEmitter.instance;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
override dispose() {
|
||||
super.dispose();
|
||||
this._subscriptions.dispose();
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export type EventHandler = HTMLElement | HTMLDocument | Window;
|
||||
|
||||
export interface IDomEvent {
|
||||
<K extends keyof HTMLElementEventMap>(element: EventHandler, type: K, useCapture?: boolean): BaseEvent<HTMLElementEventMap[K]>;
|
||||
(element: EventHandler, type: string, useCapture?: boolean): BaseEvent<any>;
|
||||
(element: EventHandler, type: string, useCapture?: boolean): BaseEvent<unknown>;
|
||||
}
|
||||
|
||||
export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => {
|
||||
|
@ -16,6 +16,7 @@ export interface FormattedTextRenderOptions {
|
||||
readonly className?: string;
|
||||
readonly inline?: boolean;
|
||||
readonly actionHandler?: IContentActionHandler;
|
||||
readonly renderCodeSegements?: boolean;
|
||||
}
|
||||
|
||||
export function renderText(text: string, options: FormattedTextRenderOptions = {}): HTMLElement {
|
||||
@ -26,7 +27,7 @@ export function renderText(text: string, options: FormattedTextRenderOptions = {
|
||||
|
||||
export function renderFormattedText(formattedText: string, options: FormattedTextRenderOptions = {}): HTMLElement {
|
||||
const element = createElement(options);
|
||||
_renderFormattedText(element, parseFormattedText(formattedText), options.actionHandler);
|
||||
_renderFormattedText(element, parseFormattedText(formattedText, !!options.renderCodeSegements), options.actionHandler, options.renderCodeSegements);
|
||||
return element;
|
||||
}
|
||||
|
||||
@ -75,6 +76,7 @@ const enum FormatType {
|
||||
Italics,
|
||||
Action,
|
||||
ActionClose,
|
||||
Code,
|
||||
NewLine
|
||||
}
|
||||
|
||||
@ -85,7 +87,7 @@ interface IFormatParseTree {
|
||||
children?: IFormatParseTree[];
|
||||
}
|
||||
|
||||
function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler) {
|
||||
function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler, renderCodeSegements?: boolean) {
|
||||
let child: Node | undefined;
|
||||
|
||||
if (treeNode.type === FormatType.Text) {
|
||||
@ -94,6 +96,8 @@ function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionH
|
||||
child = document.createElement('b');
|
||||
} else if (treeNode.type === FormatType.Italics) {
|
||||
child = document.createElement('i');
|
||||
} else if (treeNode.type === FormatType.Code && renderCodeSegements) {
|
||||
child = document.createElement('code');
|
||||
} else if (treeNode.type === FormatType.Action && actionHandler) {
|
||||
const a = document.createElement('a');
|
||||
a.href = '#';
|
||||
@ -114,12 +118,12 @@ function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionH
|
||||
|
||||
if (child && Array.isArray(treeNode.children)) {
|
||||
treeNode.children.forEach((nodeChild) => {
|
||||
_renderFormattedText(child!, nodeChild, actionHandler);
|
||||
_renderFormattedText(child!, nodeChild, actionHandler, renderCodeSegements);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseFormattedText(content: string): IFormatParseTree {
|
||||
function parseFormattedText(content: string, parseCodeSegments: boolean): IFormatParseTree {
|
||||
|
||||
const root: IFormatParseTree = {
|
||||
type: FormatType.Root,
|
||||
@ -134,19 +138,19 @@ function parseFormattedText(content: string): IFormatParseTree {
|
||||
while (!stream.eos()) {
|
||||
let next = stream.next();
|
||||
|
||||
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek()) !== FormatType.Invalid);
|
||||
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek(), parseCodeSegments) !== FormatType.Invalid);
|
||||
if (isEscapedFormatType) {
|
||||
next = stream.next(); // unread the backslash if it escapes a format tag type
|
||||
}
|
||||
|
||||
if (!isEscapedFormatType && isFormatTag(next) && next === stream.peek()) {
|
||||
if (!isEscapedFormatType && isFormatTag(next, parseCodeSegments) && next === stream.peek()) {
|
||||
stream.advance();
|
||||
|
||||
if (current.type === FormatType.Text) {
|
||||
current = stack.pop()!;
|
||||
}
|
||||
|
||||
const type = formatTagType(next);
|
||||
const type = formatTagType(next, parseCodeSegments);
|
||||
if (current.type === type || (current.type === FormatType.Action && type === FormatType.ActionClose)) {
|
||||
current = stack.pop()!;
|
||||
} else {
|
||||
@ -200,11 +204,11 @@ function parseFormattedText(content: string): IFormatParseTree {
|
||||
return root;
|
||||
}
|
||||
|
||||
function isFormatTag(char: string): boolean {
|
||||
return formatTagType(char) !== FormatType.Invalid;
|
||||
function isFormatTag(char: string, supportCodeSegments: boolean): boolean {
|
||||
return formatTagType(char, supportCodeSegments) !== FormatType.Invalid;
|
||||
}
|
||||
|
||||
function formatTagType(char: string): FormatType {
|
||||
function formatTagType(char: string, supportCodeSegments: boolean): FormatType {
|
||||
switch (char) {
|
||||
case '*':
|
||||
return FormatType.Bold;
|
||||
@ -214,6 +218,8 @@ function formatTagType(char: string): FormatType {
|
||||
return FormatType.Action;
|
||||
case ']':
|
||||
return FormatType.ActionClose;
|
||||
case '`':
|
||||
return supportCodeSegments ? FormatType.Code : FormatType.Invalid;
|
||||
default:
|
||||
return FormatType.Invalid;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ export class Gesture extends Disposable {
|
||||
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this.handle) {
|
||||
this.handle.dispose();
|
||||
this.handle = null;
|
||||
|
@ -27,12 +27,12 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
|
||||
element: HTMLElement | undefined;
|
||||
|
||||
_context: any;
|
||||
_context: unknown;
|
||||
_action: IAction;
|
||||
|
||||
private _actionRunner: IActionRunner | undefined;
|
||||
|
||||
constructor(context: any, action: IAction, protected options: IBaseActionViewItemOptions = {}) {
|
||||
constructor(context: unknown, action: IAction, protected options: IBaseActionViewItemOptions = {}) {
|
||||
super();
|
||||
|
||||
this._context = context || this;
|
||||
@ -174,6 +174,10 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
isFocused(): boolean {
|
||||
return !!this.element?.classList.contains('focused');
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
if (this.element) {
|
||||
this.element.blur();
|
||||
@ -212,7 +216,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
if (this.element) {
|
||||
this.element.remove();
|
||||
this.element = undefined;
|
||||
@ -231,7 +235,7 @@ export interface IActionViewItemOptions extends IBaseActionViewItemOptions {
|
||||
export class ActionViewItem extends BaseActionViewItem {
|
||||
|
||||
protected label: HTMLElement | undefined;
|
||||
protected options: IActionViewItemOptions;
|
||||
protected override options: IActionViewItemOptions;
|
||||
|
||||
private cssClass?: string;
|
||||
|
||||
@ -244,7 +248,7 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
this.cssClass = '';
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
|
||||
if (this.element) {
|
||||
@ -276,32 +280,36 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
|
||||
// Only set the tabIndex on the element once it is about to get focused
|
||||
// That way this element wont be a tab stop when it is not needed #106441
|
||||
focus(): void {
|
||||
override focus(): void {
|
||||
if (this.label) {
|
||||
this.label.tabIndex = 0;
|
||||
this.label.focus();
|
||||
}
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
override isFocused(): boolean {
|
||||
return !!this.label && this.label?.tabIndex === 0;
|
||||
}
|
||||
|
||||
override blur(): void {
|
||||
if (this.label) {
|
||||
this.label.tabIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
setFocusable(focusable: boolean): void {
|
||||
override setFocusable(focusable: boolean): void {
|
||||
if (this.label) {
|
||||
this.label.tabIndex = focusable ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
updateLabel(): void {
|
||||
override updateLabel(): void {
|
||||
if (this.options.label && this.label) {
|
||||
this.label.textContent = this.getAction().label;
|
||||
}
|
||||
}
|
||||
|
||||
updateTooltip(): void {
|
||||
override updateTooltip(): void {
|
||||
let title: string | null = null;
|
||||
|
||||
if (this.getAction().tooltip) {
|
||||
@ -320,7 +328,7 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateClass(): void {
|
||||
override updateClass(): void {
|
||||
if (this.cssClass && this.label) {
|
||||
this.label.classList.remove(...this.cssClass.split(' '));
|
||||
}
|
||||
@ -343,7 +351,7 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateEnabled(): void {
|
||||
override updateEnabled(): void {
|
||||
if (this.getAction().enabled) {
|
||||
if (this.label) {
|
||||
this.label.removeAttribute('aria-disabled');
|
||||
@ -365,7 +373,7 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateChecked(): void {
|
||||
override updateChecked(): void {
|
||||
if (this.label) {
|
||||
if (this.getAction().checked) {
|
||||
this.label.classList.add('checked');
|
||||
@ -407,23 +415,23 @@ export class SelectActionViewItem extends BaseActionViewItem {
|
||||
return option;
|
||||
}
|
||||
|
||||
setFocusable(focusable: boolean): void {
|
||||
override setFocusable(focusable: boolean): void {
|
||||
this.selectBox.setFocusable(focusable);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
override focus(): void {
|
||||
if (this.selectBox) {
|
||||
this.selectBox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
override blur(): void {
|
||||
if (this.selectBox) {
|
||||
this.selectBox.blur();
|
||||
}
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
this.selectBox.render(container);
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-action-bar {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-action-bar .actions-container {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .actions-container {
|
||||
@ -21,9 +22,10 @@
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item {
|
||||
display: block;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
transition: transform 50ms ease;
|
||||
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
|
||||
}
|
||||
|
||||
@ -31,23 +33,22 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated .action-item.active {
|
||||
transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .icon,
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-label {
|
||||
font-size: 11px;
|
||||
margin-right: 4px;
|
||||
padding: 3px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled .action-label,
|
||||
@ -74,10 +75,6 @@
|
||||
margin-right: .8em;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated.vertical .action-item.active {
|
||||
transform: translate(5px, 0);
|
||||
}
|
||||
|
||||
.secondary-actions .monaco-action-bar .action-label {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import { IActionViewItemOptions, ActionViewItem, BaseActionViewItem } from 'vs/b
|
||||
|
||||
export interface IActionViewItem extends IDisposable {
|
||||
actionRunner: IActionRunner;
|
||||
setActionContext(context: any): void;
|
||||
setActionContext(context: unknown): void;
|
||||
render(element: HTMLElement): void;
|
||||
isEnabled(): boolean;
|
||||
focus(fromRight?: boolean): void; // TODO@isidorn what is this?
|
||||
@ -38,7 +38,7 @@ export interface ActionTrigger {
|
||||
|
||||
export interface IActionBarOptions {
|
||||
readonly orientation?: ActionsOrientation;
|
||||
readonly context?: any;
|
||||
readonly context?: unknown;
|
||||
readonly actionViewItemProvider?: IActionViewItemProvider;
|
||||
readonly actionRunner?: IActionRunner;
|
||||
readonly ariaLabel?: string;
|
||||
@ -264,11 +264,11 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
get context(): any {
|
||||
get context(): unknown {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
set context(context: any) {
|
||||
set context(context: unknown) {
|
||||
this._context = context;
|
||||
this.viewItems.forEach(i => i.setActionContext(context));
|
||||
}
|
||||
@ -525,11 +525,11 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
run(action: IAction, context?: unknown): Promise<void> {
|
||||
return this._actionRunner.run(action, context);
|
||||
async run(action: IAction, context?: unknown): Promise<void> {
|
||||
await this._actionRunner.run(action, context);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
dispose(this.viewItems);
|
||||
this.viewItems = [];
|
||||
|
||||
|
@ -24,6 +24,9 @@
|
||||
height: 100%;
|
||||
outline: none;
|
||||
}
|
||||
.monaco-breadcrumbs.disabled .monaco-breadcrumb-item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-breadcrumb-separator {
|
||||
color: inherit;
|
||||
|
@ -56,6 +56,7 @@ export class BreadcrumbsWidget {
|
||||
private readonly _nodes = new Array<HTMLDivElement>();
|
||||
private readonly _freeNodes = new Array<HTMLDivElement>();
|
||||
|
||||
private _enabled: boolean = true;
|
||||
private _focusedItemIdx: number = -1;
|
||||
private _selectedItemIdx: number = -1;
|
||||
|
||||
@ -155,13 +156,18 @@ export class BreadcrumbsWidget {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused.selected { color: ${style.breadcrumbsFocusAndSelectionForeground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsHoverForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item:hover:not(.focused):not(.selected) { color: ${style.breadcrumbsHoverForeground}}\n`;
|
||||
content += `.monaco-breadcrumbs:not(.disabled ) .monaco-breadcrumb-item:hover:not(.focused):not(.selected) { color: ${style.breadcrumbsHoverForeground}}\n`;
|
||||
}
|
||||
if (this._styleElement.innerText !== content) {
|
||||
this._styleElement.innerText = content;
|
||||
}
|
||||
}
|
||||
|
||||
setEnabled(value: boolean) {
|
||||
this._enabled = value;
|
||||
this._domNode.classList.toggle('disabled', !this._enabled);
|
||||
}
|
||||
|
||||
domFocus(): void {
|
||||
let idx = this._focusedItemIdx >= 0 ? this._focusedItemIdx : this._items.length - 1;
|
||||
if (idx >= 0 && idx < this._items.length) {
|
||||
@ -326,6 +332,9 @@ export class BreadcrumbsWidget {
|
||||
}
|
||||
|
||||
private _onClick(event: IMouseEvent): void {
|
||||
if (!this._enabled) {
|
||||
return;
|
||||
}
|
||||
for (let el: HTMLElement | null = event.target; el; el = el.parentElement) {
|
||||
let idx = this._nodes.indexOf(el as HTMLDivElement);
|
||||
if (idx >= 0) {
|
||||
|
@ -22,8 +22,9 @@
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.monaco-button.disabled:focus,
|
||||
.monaco-button.disabled {
|
||||
opacity: 0.4;
|
||||
opacity: 0.4 !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@ -39,3 +40,15 @@
|
||||
.monaco-button-dropdown > .monaco-dropdown-button {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.monaco-description-button {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.monaco-description-button .monaco-button-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.monaco-description-button .monaco-button-description {
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ export interface IButton extends IDisposable {
|
||||
hasFocus(): boolean;
|
||||
}
|
||||
|
||||
export interface IButtonWithDescription extends IButton {
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class Button extends Disposable implements IButton {
|
||||
|
||||
private _element: HTMLElement;
|
||||
@ -303,6 +307,207 @@ export class ButtonWithDropdown extends Disposable implements IButton {
|
||||
}
|
||||
}
|
||||
|
||||
export class ButtonWithDescription extends Disposable implements IButtonWithDescription {
|
||||
|
||||
private _element: HTMLElement;
|
||||
private _labelElement: HTMLElement;
|
||||
private _descriptionElement: HTMLElement;
|
||||
private options: IButtonOptions;
|
||||
|
||||
private buttonBackground: Color | undefined;
|
||||
private buttonHoverBackground: Color | undefined;
|
||||
private buttonForeground: Color | undefined;
|
||||
private buttonSecondaryBackground: Color | undefined;
|
||||
private buttonSecondaryHoverBackground: Color | undefined;
|
||||
private buttonSecondaryForeground: Color | undefined;
|
||||
private buttonBorder: Color | undefined;
|
||||
|
||||
private _onDidClick = this._register(new Emitter<Event>());
|
||||
get onDidClick(): BaseEvent<Event> { return this._onDidClick.event; }
|
||||
|
||||
private focusTracker: IFocusTracker;
|
||||
|
||||
constructor(container: HTMLElement, options?: IButtonOptions) {
|
||||
super();
|
||||
|
||||
this.options = options || Object.create(null);
|
||||
mixin(this.options, defaultOptions, false);
|
||||
|
||||
this.buttonForeground = this.options.buttonForeground;
|
||||
this.buttonBackground = this.options.buttonBackground;
|
||||
this.buttonHoverBackground = this.options.buttonHoverBackground;
|
||||
|
||||
this.buttonSecondaryForeground = this.options.buttonSecondaryForeground;
|
||||
this.buttonSecondaryBackground = this.options.buttonSecondaryBackground;
|
||||
this.buttonSecondaryHoverBackground = this.options.buttonSecondaryHoverBackground;
|
||||
|
||||
this.buttonBorder = this.options.buttonBorder;
|
||||
|
||||
this._element = document.createElement('a');
|
||||
this._element.classList.add('monaco-button');
|
||||
this._element.classList.add('monaco-description-button');
|
||||
this._element.tabIndex = 0;
|
||||
this._element.setAttribute('role', 'button');
|
||||
|
||||
this._labelElement = document.createElement('div');
|
||||
this._labelElement.classList.add('monaco-button-label');
|
||||
this._labelElement.tabIndex = -1;
|
||||
this._element.appendChild(this._labelElement);
|
||||
|
||||
this._descriptionElement = document.createElement('div');
|
||||
this._descriptionElement.classList.add('monaco-button-description');
|
||||
this._descriptionElement.tabIndex = -1;
|
||||
this._element.appendChild(this._descriptionElement);
|
||||
|
||||
container.appendChild(this._element);
|
||||
|
||||
this._register(Gesture.addTarget(this._element));
|
||||
|
||||
[EventType.CLICK, TouchEventType.Tap].forEach(eventType => {
|
||||
this._register(addDisposableListener(this._element, eventType, e => {
|
||||
if (!this.enabled) {
|
||||
EventHelper.stop(e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._onDidClick.fire(e);
|
||||
}));
|
||||
});
|
||||
|
||||
this._register(addDisposableListener(this._element, EventType.KEY_DOWN, e => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
let eventHandled = false;
|
||||
if (this.enabled && (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) {
|
||||
this._onDidClick.fire(e);
|
||||
eventHandled = true;
|
||||
} else if (event.equals(KeyCode.Escape)) {
|
||||
this._element.blur();
|
||||
eventHandled = true;
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
EventHelper.stop(event, true);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(addDisposableListener(this._element, EventType.MOUSE_OVER, e => {
|
||||
if (!this._element.classList.contains('disabled')) {
|
||||
this.setHoverBackground();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(addDisposableListener(this._element, EventType.MOUSE_OUT, e => {
|
||||
this.applyStyles(); // restore standard styles
|
||||
}));
|
||||
|
||||
// Also set hover background when button is focused for feedback
|
||||
this.focusTracker = this._register(trackFocus(this._element));
|
||||
this._register(this.focusTracker.onDidFocus(() => this.setHoverBackground()));
|
||||
this._register(this.focusTracker.onDidBlur(() => this.applyStyles())); // restore standard styles
|
||||
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
private setHoverBackground(): void {
|
||||
let hoverBackground;
|
||||
if (this.options.secondary) {
|
||||
hoverBackground = this.buttonSecondaryHoverBackground ? this.buttonSecondaryHoverBackground.toString() : null;
|
||||
} else {
|
||||
hoverBackground = this.buttonHoverBackground ? this.buttonHoverBackground.toString() : null;
|
||||
}
|
||||
if (hoverBackground) {
|
||||
this._element.style.backgroundColor = hoverBackground;
|
||||
}
|
||||
}
|
||||
|
||||
style(styles: IButtonStyles): void {
|
||||
this.buttonForeground = styles.buttonForeground;
|
||||
this.buttonBackground = styles.buttonBackground;
|
||||
this.buttonHoverBackground = styles.buttonHoverBackground;
|
||||
this.buttonSecondaryForeground = styles.buttonSecondaryForeground;
|
||||
this.buttonSecondaryBackground = styles.buttonSecondaryBackground;
|
||||
this.buttonSecondaryHoverBackground = styles.buttonSecondaryHoverBackground;
|
||||
this.buttonBorder = styles.buttonBorder;
|
||||
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
private applyStyles(): void {
|
||||
if (this._element) {
|
||||
let background, foreground;
|
||||
if (this.options.secondary) {
|
||||
foreground = this.buttonSecondaryForeground ? this.buttonSecondaryForeground.toString() : '';
|
||||
background = this.buttonSecondaryBackground ? this.buttonSecondaryBackground.toString() : '';
|
||||
} else {
|
||||
foreground = this.buttonForeground ? this.buttonForeground.toString() : '';
|
||||
background = this.buttonBackground ? this.buttonBackground.toString() : '';
|
||||
}
|
||||
|
||||
const border = this.buttonBorder ? this.buttonBorder.toString() : '';
|
||||
|
||||
this._element.style.color = foreground;
|
||||
this._element.style.backgroundColor = background;
|
||||
|
||||
this._element.style.borderWidth = border ? '1px' : '';
|
||||
this._element.style.borderStyle = border ? 'solid' : '';
|
||||
this._element.style.borderColor = border;
|
||||
}
|
||||
}
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
set label(value: string) {
|
||||
this._element.classList.add('monaco-text-button');
|
||||
if (this.options.supportIcons) {
|
||||
reset(this._labelElement, ...renderLabelWithIcons(value));
|
||||
} else {
|
||||
this._labelElement.textContent = value;
|
||||
}
|
||||
if (typeof this.options.title === 'string') {
|
||||
this._element.title = this.options.title;
|
||||
} else if (this.options.title) {
|
||||
this._element.title = value;
|
||||
}
|
||||
}
|
||||
|
||||
set description(value: string) {
|
||||
if (this.options.supportIcons) {
|
||||
reset(this._descriptionElement, ...renderLabelWithIcons(value));
|
||||
} else {
|
||||
this._descriptionElement.textContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
set icon(icon: CSSIcon) {
|
||||
this._element.classList.add(...CSSIcon.asClassNameArray(icon));
|
||||
}
|
||||
|
||||
set enabled(value: boolean) {
|
||||
if (value) {
|
||||
this._element.classList.remove('disabled');
|
||||
this._element.setAttribute('aria-disabled', String(false));
|
||||
this._element.tabIndex = 0;
|
||||
} else {
|
||||
this._element.classList.add('disabled');
|
||||
this._element.setAttribute('aria-disabled', String(true));
|
||||
}
|
||||
}
|
||||
|
||||
get enabled() {
|
||||
return !this._element.classList.contains('disabled');
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._element.focus();
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
return this._element === document.activeElement;
|
||||
}
|
||||
}
|
||||
|
||||
export class ButtonBar extends Disposable {
|
||||
|
||||
private _buttons: IButton[] = [];
|
||||
@ -321,6 +526,12 @@ export class ButtonBar extends Disposable {
|
||||
return button;
|
||||
}
|
||||
|
||||
addButtonWithDescription(options?: IButtonOptions): IButtonWithDescription {
|
||||
const button = this._register(new ButtonWithDescription(this.container, options));
|
||||
this.pushButton(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
addButtonWithDropdown(options: IButtonWithDropdownOptions): IButton {
|
||||
const button = this._register(new ButtonWithDropdown(this.container, options));
|
||||
this.pushButton(button);
|
||||
|
@ -44,7 +44,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
|
||||
protected checkbox: Checkbox | undefined;
|
||||
protected readonly disposables = new DisposableStore();
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
this.element = container;
|
||||
|
||||
this.disposables.clear();
|
||||
@ -59,7 +59,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
|
||||
this.element.appendChild(this.checkbox.domNode);
|
||||
}
|
||||
|
||||
updateEnabled(): void {
|
||||
override updateEnabled(): void {
|
||||
if (this.checkbox) {
|
||||
if (this.isEnabled()) {
|
||||
this.checkbox.enable();
|
||||
@ -69,33 +69,33 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateChecked(): void {
|
||||
override updateChecked(): void {
|
||||
if (this.checkbox) {
|
||||
this.checkbox.checked = this._action.checked;
|
||||
}
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
override focus(): void {
|
||||
if (this.checkbox) {
|
||||
this.checkbox.domNode.tabIndex = 0;
|
||||
this.checkbox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
override blur(): void {
|
||||
if (this.checkbox) {
|
||||
this.checkbox.domNode.tabIndex = -1;
|
||||
this.checkbox.domNode.blur();
|
||||
}
|
||||
}
|
||||
|
||||
setFocusable(focusable: boolean): void {
|
||||
override setFocusable(focusable: boolean): void {
|
||||
if (this.checkbox) {
|
||||
this.checkbox.domNode.tabIndex = focusable ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.disposables.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
@ -13,7 +13,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.codicon-sync.codicon-modifier-spin, .codicon-loading.codicon-modifier-spin, .codicon-gear.codicon-modifier-spin {
|
||||
.codicon-sync.codicon-modifier-spin,
|
||||
.codicon-loading.codicon-modifier-spin,
|
||||
.codicon-gear.codicon-modifier-spin,
|
||||
.codicon-notebook-state-executing.codicon-modifier-spin {
|
||||
/* Use steps to throttle FPS to reduce CPU usage */
|
||||
animation: codicon-spin 1.5s steps(30) infinite;
|
||||
}
|
||||
|
Binary file not shown.
@ -45,7 +45,7 @@ export interface IDelegate {
|
||||
anchorAxisAlignment?: AnchorAxisAlignment; // default: vertical
|
||||
canRelayout?: boolean; // default: true
|
||||
onDOMEvent?(e: Event, activeElement: HTMLElement): void;
|
||||
onHide?(data?: any): void;
|
||||
onHide?(data?: unknown): void;
|
||||
}
|
||||
|
||||
export interface IContextViewProvider {
|
||||
@ -324,7 +324,7 @@ export class ContextView extends Disposable {
|
||||
this.view.style.width = 'initial';
|
||||
}
|
||||
|
||||
hide(data?: any): void {
|
||||
hide(data?: unknown): void {
|
||||
const delegate = this.delegate;
|
||||
this.delegate = null;
|
||||
|
||||
@ -351,7 +351,7 @@ export class ContextView extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.hide();
|
||||
|
||||
super.dispose();
|
||||
|
@ -10,7 +10,7 @@
|
||||
width: 100%;
|
||||
left:0;
|
||||
top:0;
|
||||
z-index: 2000;
|
||||
z-index: 2600;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -34,17 +34,12 @@
|
||||
|
||||
/** Dialog: Title Actions Row */
|
||||
.monaco-dialog-box .dialog-toolbar-row {
|
||||
height: 22px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.monaco-dialog-box .action-label {
|
||||
height: 16px;
|
||||
min-width: 16px;
|
||||
background-size: 16px;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
margin: 0px;
|
||||
margin-left: 4px;
|
||||
.monaco-dialog-box .dialog-toolbar-row .actions-container {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/** Dialog: Message Row */
|
||||
@ -144,6 +139,10 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-dialog-box > .dialog-buttons-row > .dialog-buttons.centered {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-dialog-box > .dialog-buttons-row > .dialog-buttons > .monaco-button {
|
||||
width: fit-content;
|
||||
width: -moz-fit-content;
|
||||
|
@ -11,7 +11,7 @@ import { domEvent } from 'vs/base/browser/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { ButtonBar, IButtonStyles } from 'vs/base/browser/ui/button/button';
|
||||
import { ButtonBar, ButtonWithDescription, IButtonStyles } from 'vs/base/browser/ui/button/button';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
@ -34,6 +34,10 @@ export interface IDialogOptions {
|
||||
readonly type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
|
||||
readonly inputs?: IDialogInputOptions[];
|
||||
readonly keyEventProcessor?: (event: StandardKeyboardEvent) => void;
|
||||
readonly renderBody?: (container: HTMLElement) => void;
|
||||
readonly icon?: Codicon;
|
||||
readonly buttonDetails?: string[];
|
||||
readonly disableCloseAction?: boolean;
|
||||
}
|
||||
|
||||
export interface IDialogResult {
|
||||
@ -53,6 +57,8 @@ export interface IDialogStyles extends IButtonStyles, ISimpleCheckboxStyles {
|
||||
readonly inputBackground?: Color;
|
||||
readonly inputForeground?: Color;
|
||||
readonly inputBorder?: Color;
|
||||
readonly textLinkForeground?: Color;
|
||||
|
||||
}
|
||||
|
||||
interface ButtonMapEntry {
|
||||
@ -71,6 +77,7 @@ export class Dialog extends Disposable {
|
||||
private modalElement: HTMLElement | undefined;
|
||||
private readonly buttonsContainer: HTMLElement;
|
||||
private readonly messageDetailElement: HTMLElement;
|
||||
private readonly messageContainer: HTMLElement;
|
||||
private readonly iconElement: HTMLElement;
|
||||
private readonly checkbox: SimpleCheckbox | undefined;
|
||||
private readonly toolbarContainer: HTMLElement;
|
||||
@ -83,7 +90,7 @@ export class Dialog extends Disposable {
|
||||
constructor(private container: HTMLElement, private message: string, buttons: string[], private options: IDialogOptions) {
|
||||
super();
|
||||
|
||||
this.modalElement = this.container.appendChild($(`.monaco-dialog-modal-block${options.type === 'pending' ? '.dimmed' : ''}`));
|
||||
this.modalElement = this.container.appendChild($(`.monaco-dialog-modal-block.dimmed`));
|
||||
this.shadowElement = this.modalElement.appendChild($('.dialog-shadow'));
|
||||
this.element = this.shadowElement.appendChild($('.monaco-dialog-box'));
|
||||
this.element.setAttribute('role', 'dialog');
|
||||
@ -95,20 +102,29 @@ export class Dialog extends Disposable {
|
||||
|
||||
const messageRowElement = this.element.appendChild($('.dialog-message-row'));
|
||||
this.iconElement = messageRowElement.appendChild($('.dialog-icon'));
|
||||
const messageContainer = messageRowElement.appendChild($('.dialog-message-container'));
|
||||
this.messageContainer = messageRowElement.appendChild($('.dialog-message-container'));
|
||||
|
||||
if (this.options.detail) {
|
||||
const messageElement = messageContainer.appendChild($('.dialog-message'));
|
||||
if (this.options.detail || this.options.renderBody) {
|
||||
const messageElement = this.messageContainer.appendChild($('.dialog-message'));
|
||||
const messageTextElement = messageElement.appendChild($('.dialog-message-text'));
|
||||
messageTextElement.innerText = this.message;
|
||||
}
|
||||
|
||||
this.messageDetailElement = messageContainer.appendChild($('.dialog-message-detail'));
|
||||
this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
|
||||
this.messageDetailElement = this.messageContainer.appendChild($('.dialog-message-detail'));
|
||||
if (this.options.detail || !this.options.renderBody) {
|
||||
this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
|
||||
} else {
|
||||
this.messageDetailElement.style.display = 'none';
|
||||
}
|
||||
|
||||
if (this.options.renderBody) {
|
||||
const customBody = this.messageContainer.appendChild($('.dialog-message-body'));
|
||||
this.options.renderBody(customBody);
|
||||
}
|
||||
|
||||
if (this.options.inputs) {
|
||||
this.inputs = this.options.inputs.map(input => {
|
||||
const inputRowElement = messageContainer.appendChild($('.dialog-message-input'));
|
||||
const inputRowElement = this.messageContainer.appendChild($('.dialog-message-input'));
|
||||
|
||||
const inputBox = this._register(new InputBox(inputRowElement, undefined, {
|
||||
placeholder: input.placeholder,
|
||||
@ -126,7 +142,7 @@ export class Dialog extends Disposable {
|
||||
}
|
||||
|
||||
if (this.options.checkboxLabel) {
|
||||
const checkboxRowElement = messageContainer.appendChild($('.dialog-checkbox-row'));
|
||||
const checkboxRowElement = this.messageContainer.appendChild($('.dialog-checkbox-row'));
|
||||
|
||||
const checkbox = this.checkbox = this._register(new SimpleCheckbox(this.options.checkboxLabel, !!this.options.checkboxChecked));
|
||||
|
||||
@ -175,12 +191,16 @@ export class Dialog extends Disposable {
|
||||
|
||||
const buttonBar = this.buttonBar = this._register(new ButtonBar(this.buttonsContainer));
|
||||
const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId);
|
||||
this.buttonsContainer.classList.toggle('centered');
|
||||
|
||||
// Handle button clicks
|
||||
buttonMap.forEach((entry, index) => {
|
||||
const button = this._register(buttonBar.addButton({ title: true }));
|
||||
const primary = buttonMap[index].index === 0;
|
||||
const button = this.options.buttonDetails ? this._register(buttonBar.addButtonWithDescription({ title: true, secondary: !primary })) : this._register(buttonBar.addButton({ title: true, secondary: !primary }));
|
||||
button.label = mnemonicButtonLabel(buttonMap[index].label, true);
|
||||
|
||||
if (button instanceof ButtonWithDescription) {
|
||||
button.description = this.options.buttonDetails![buttonMap[index].index];
|
||||
}
|
||||
this._register(button.onDidClick(e => {
|
||||
if (e) {
|
||||
EventHelper.stop(e);
|
||||
@ -287,7 +307,7 @@ export class Dialog extends Disposable {
|
||||
EventHelper.stop(e, true);
|
||||
const evt = new StandardKeyboardEvent(e);
|
||||
|
||||
if (evt.equals(KeyCode.Escape)) {
|
||||
if (!this.options.disableCloseAction && evt.equals(KeyCode.Escape)) {
|
||||
resolve({
|
||||
button: this.options.cancelId || 0,
|
||||
checkboxChecked: this.checkbox ? this.checkbox.checked : undefined
|
||||
@ -313,34 +333,41 @@ export class Dialog extends Disposable {
|
||||
|
||||
this.iconElement.classList.remove(...dialogErrorIcon.classNamesArray, ...dialogWarningIcon.classNamesArray, ...dialogInfoIcon.classNamesArray, ...Codicon.loading.classNamesArray, spinModifierClassName);
|
||||
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
this.iconElement.classList.add(...dialogErrorIcon.classNamesArray);
|
||||
break;
|
||||
case 'warning':
|
||||
this.iconElement.classList.add(...dialogWarningIcon.classNamesArray);
|
||||
break;
|
||||
case 'pending':
|
||||
this.iconElement.classList.add(...Codicon.loading.classNamesArray, spinModifierClassName);
|
||||
break;
|
||||
case 'none':
|
||||
case 'info':
|
||||
case 'question':
|
||||
default:
|
||||
this.iconElement.classList.add(...dialogInfoIcon.classNamesArray);
|
||||
break;
|
||||
if (this.options.icon) {
|
||||
this.iconElement.classList.add(...this.options.icon.classNamesArray);
|
||||
} else {
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
this.iconElement.classList.add(...dialogErrorIcon.classNamesArray);
|
||||
break;
|
||||
case 'warning':
|
||||
this.iconElement.classList.add(...dialogWarningIcon.classNamesArray);
|
||||
break;
|
||||
case 'pending':
|
||||
this.iconElement.classList.add(...Codicon.loading.classNamesArray, spinModifierClassName);
|
||||
break;
|
||||
case 'none':
|
||||
case 'info':
|
||||
case 'question':
|
||||
default:
|
||||
this.iconElement.classList.add(...dialogInfoIcon.classNamesArray);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const actionBar = this._register(new ActionBar(this.toolbarContainer, {}));
|
||||
|
||||
const action = this._register(new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), dialogCloseIcon.classNames, true, async () => {
|
||||
resolve({
|
||||
button: this.options.cancelId || 0,
|
||||
checkboxChecked: this.checkbox ? this.checkbox.checked : undefined
|
||||
});
|
||||
}));
|
||||
if (!this.options.disableCloseAction) {
|
||||
const actionBar = this._register(new ActionBar(this.toolbarContainer, {}));
|
||||
|
||||
actionBar.push(action, { icon: true, label: false, });
|
||||
const action = this._register(new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), dialogCloseIcon.classNames, true, async () => {
|
||||
resolve({
|
||||
button: this.options.cancelId || 0,
|
||||
checkboxChecked: this.checkbox ? this.checkbox.checked : undefined
|
||||
});
|
||||
}));
|
||||
|
||||
actionBar.push(action, { icon: true, label: false, });
|
||||
}
|
||||
|
||||
this.applyStyles();
|
||||
|
||||
@ -369,6 +396,7 @@ export class Dialog extends Disposable {
|
||||
const bgColor = style.dialogBackground;
|
||||
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
|
||||
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
|
||||
const linkFgColor = style.textLinkForeground;
|
||||
|
||||
this.shadowElement.style.boxShadow = shadowColor;
|
||||
|
||||
@ -389,6 +417,12 @@ export class Dialog extends Disposable {
|
||||
this.messageDetailElement.style.color = messageDetailColor.makeOpaque(bgColor).toString();
|
||||
}
|
||||
|
||||
if (linkFgColor) {
|
||||
for (const el of this.messageContainer.getElementsByTagName('a')) {
|
||||
el.style.color = linkFgColor.toString();
|
||||
}
|
||||
}
|
||||
|
||||
let color;
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
@ -417,7 +451,7 @@ export class Dialog extends Disposable {
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (this.modalElement) {
|
||||
|
@ -11,8 +11,29 @@
|
||||
.monaco-dropdown > .dropdown-label {
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-dropdown > .dropdown-label > .action-label.disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-dropdown-with-primary {
|
||||
display: flex !important;
|
||||
flex-direction: row;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.monaco-dropdown-with-primary > .action-container > .action-label {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label .codicon[class*='codicon-'] {
|
||||
font-size: 12px;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
line-height: 16px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ export class BaseDropdown extends ActionRunner {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
this.hide();
|
||||
|
||||
@ -159,7 +159,7 @@ export class Dropdown extends BaseDropdown {
|
||||
this.contextViewProvider = options.contextViewProvider;
|
||||
}
|
||||
|
||||
show(): void {
|
||||
override show(): void {
|
||||
super.show();
|
||||
|
||||
this.element.classList.add('active');
|
||||
@ -187,7 +187,7 @@ export class Dropdown extends BaseDropdown {
|
||||
this.element.classList.remove('active');
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
override hide(): void {
|
||||
super.hide();
|
||||
|
||||
if (this.contextViewProvider) {
|
||||
@ -250,7 +250,7 @@ export class DropdownMenu extends BaseDropdown {
|
||||
this._actions = actions;
|
||||
}
|
||||
|
||||
show(): void {
|
||||
override show(): void {
|
||||
super.show();
|
||||
|
||||
this.element.classList.add('active');
|
||||
@ -269,7 +269,7 @@ export class DropdownMenu extends BaseDropdown {
|
||||
});
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
override hide(): void {
|
||||
super.hide();
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,15 @@ import 'vs/css!./dropdown';
|
||||
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { append, $, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ActionViewItem, BaseActionViewItem, IActionViewItemOptions, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { IActionProvider, DropdownMenu, IDropdownMenuOptions, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
||||
export interface IKeybindingProvider {
|
||||
(action: IAction): ResolvedKeybinding | undefined;
|
||||
@ -42,23 +43,26 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
|
||||
|
||||
protected override readonly options: IDropdownMenuActionViewItemOptions;
|
||||
|
||||
constructor(
|
||||
action: IAction,
|
||||
menuActionsOrProvider: readonly IAction[] | IActionProvider,
|
||||
contextMenuProvider: IContextMenuProvider,
|
||||
protected options: IDropdownMenuActionViewItemOptions = {}
|
||||
options: IDropdownMenuActionViewItemOptions = Object.create(null)
|
||||
) {
|
||||
super(null, action, options);
|
||||
|
||||
this.menuActionsOrProvider = menuActionsOrProvider;
|
||||
this.contextMenuProvider = contextMenuProvider;
|
||||
this.options = options;
|
||||
|
||||
if (this.options.actionRunner) {
|
||||
this.actionRunner = this.options.actionRunner;
|
||||
}
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
this.actionItem = container;
|
||||
|
||||
const labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {
|
||||
@ -123,7 +127,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
this.updateEnabled();
|
||||
}
|
||||
|
||||
setActionContext(newContext: unknown): void {
|
||||
override setActionContext(newContext: unknown): void {
|
||||
super.setActionContext(newContext);
|
||||
|
||||
if (this.dropdownMenu) {
|
||||
@ -141,7 +145,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
protected updateEnabled(): void {
|
||||
protected override updateEnabled(): void {
|
||||
const disabled = !this.getAction().enabled;
|
||||
this.actionItem?.classList.toggle('disabled', disabled);
|
||||
this.element?.classList.toggle('disabled', disabled);
|
||||
@ -166,7 +170,7 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem {
|
||||
super(context, action, options);
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
if (this.element) {
|
||||
this.element.classList.add('action-dropdown-item');
|
||||
@ -181,6 +185,36 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem {
|
||||
};
|
||||
this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', undefined)), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...(<IActionWithDropdownActionViewItemOptions>this.options).menuActionClassNames || []] });
|
||||
this.dropdownMenuActionViewItem.render(this.element);
|
||||
|
||||
this._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
let handled: boolean = false;
|
||||
if (this.dropdownMenuActionViewItem?.isFocused() && event.equals(KeyCode.LeftArrow)) {
|
||||
handled = true;
|
||||
this.dropdownMenuActionViewItem?.blur();
|
||||
this.focus();
|
||||
} else if (this.isFocused() && event.equals(KeyCode.RightArrow)) {
|
||||
handled = true;
|
||||
this.blur();
|
||||
this.dropdownMenuActionViewItem?.focus();
|
||||
}
|
||||
if (handled) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
override blur(): void {
|
||||
super.blur();
|
||||
this.dropdownMenuActionViewItem?.blur();
|
||||
}
|
||||
|
||||
override setFocusable(focusable: boolean): void {
|
||||
super.setFocusable(focusable);
|
||||
this.dropdownMenuActionViewItem?.setFocusable(focusable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,106 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
|
||||
import { ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem {
|
||||
private _primaryAction: ActionViewItem;
|
||||
private _dropdown: DropdownMenuActionViewItem;
|
||||
private _container: HTMLElement | null = null;
|
||||
private toDispose: IDisposable[];
|
||||
|
||||
constructor(
|
||||
primaryAction: IAction,
|
||||
dropdownAction: IAction,
|
||||
dropdownMenuActions: IAction[],
|
||||
_className: string,
|
||||
private readonly _contextMenuProvider: IContextMenuProvider,
|
||||
dropdownIcon?: string
|
||||
) {
|
||||
super(null, primaryAction);
|
||||
this._primaryAction = new ActionViewItem(undefined, primaryAction, {
|
||||
icon: true,
|
||||
label: false
|
||||
});
|
||||
this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, {
|
||||
menuAsChild: true
|
||||
});
|
||||
this.toDispose = [];
|
||||
}
|
||||
|
||||
override render(container: HTMLElement): void {
|
||||
this._container = container;
|
||||
super.render(this._container);
|
||||
this._container.classList.add('monaco-dropdown-with-primary');
|
||||
const primaryContainer = DOM.$('.action-container');
|
||||
this._primaryAction.render(DOM.append(this._container, primaryContainer));
|
||||
const dropdownContainer = DOM.$('.dropdown-action-container');
|
||||
this._dropdown.render(DOM.append(this._container, dropdownContainer));
|
||||
|
||||
this.toDispose.push(DOM.addDisposableListener(primaryContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.RightArrow)) {
|
||||
this._primaryAction.element!.tabIndex = -1;
|
||||
this._dropdown.focus();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(DOM.addDisposableListener(dropdownContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.LeftArrow)) {
|
||||
this._primaryAction.element!.tabIndex = 0;
|
||||
this._dropdown.setFocusable(false);
|
||||
this._primaryAction.element?.focus();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
override focus(fromRight?: boolean): void {
|
||||
if (fromRight) {
|
||||
this._dropdown.focus();
|
||||
} else {
|
||||
this._primaryAction.element!.tabIndex = 0;
|
||||
this._primaryAction.element!.focus();
|
||||
}
|
||||
}
|
||||
|
||||
override blur(): void {
|
||||
this._primaryAction.element!.tabIndex = -1;
|
||||
this._dropdown.blur();
|
||||
this._container!.blur();
|
||||
}
|
||||
|
||||
override setFocusable(focusable: boolean): void {
|
||||
if (focusable) {
|
||||
this._primaryAction.element!.tabIndex = 0;
|
||||
} else {
|
||||
this._primaryAction.element!.tabIndex = -1;
|
||||
this._dropdown.setFocusable(false);
|
||||
}
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
|
||||
update(dropdownAction: IAction, dropdownMenuActions: IAction[], dropdownIcon?: string): void {
|
||||
this._dropdown?.dispose();
|
||||
this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, {
|
||||
menuAsChild: true,
|
||||
classNames: ['codicon', dropdownIcon || 'codicon-chevron-down']
|
||||
});
|
||||
if (this.element) {
|
||||
this._dropdown.render(this.element);
|
||||
}
|
||||
}
|
||||
}
|
@ -382,7 +382,7 @@ export class ReplaceInput extends Widget {
|
||||
this.domNode.style.width = newWidth + 'px';
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -521,51 +521,6 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
return { type: 'branch', data: node.children.map(c => SerializableGrid.serializeNode(c, orthogonal(orientation))), size };
|
||||
}
|
||||
|
||||
private static deserializeNode<T extends ISerializableView>(json: ISerializedNode, orientation: Orientation, box: Box, deserializer: IViewDeserializer<T>): GridNode<T> {
|
||||
if (!json || typeof json !== 'object') {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
|
||||
if (json.type === 'branch') {
|
||||
if (!Array.isArray(json.data)) {
|
||||
throw new Error('Invalid JSON: \'data\' property of branch must be an array.');
|
||||
}
|
||||
|
||||
const children: GridNode<T>[] = [];
|
||||
let offset = 0;
|
||||
|
||||
for (const child of json.data) {
|
||||
if (typeof child.size !== 'number') {
|
||||
throw new Error('Invalid JSON: \'size\' property of node must be a number.');
|
||||
}
|
||||
|
||||
const childSize = child.type === 'leaf' && child.visible === false ? 0 : child.size;
|
||||
const childBox: Box = orientation === Orientation.HORIZONTAL
|
||||
? { top: box.top, left: box.left + offset, width: childSize, height: box.height }
|
||||
: { top: box.top + offset, left: box.left, width: box.width, height: childSize };
|
||||
|
||||
children.push(SerializableGrid.deserializeNode(child, orthogonal(orientation), childBox, deserializer));
|
||||
offset += childSize;
|
||||
}
|
||||
|
||||
return { children, box };
|
||||
|
||||
} else if (json.type === 'leaf') {
|
||||
const view: T = deserializer.fromJSON(json.data);
|
||||
return { view, box, cachedVisibleSize: json.visible === false ? json.size : undefined };
|
||||
}
|
||||
|
||||
throw new Error('Invalid JSON: \'type\' property must be either \'branch\' or \'leaf\'.');
|
||||
}
|
||||
|
||||
private static getFirstLeaf<T extends IView>(node: GridNode<T>): GridLeafNode<T> {
|
||||
if (!isGridBranchNode(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
return SerializableGrid.getFirstLeaf(node.children[0]);
|
||||
}
|
||||
|
||||
static deserialize<T extends ISerializableView>(json: ISerializedGrid, deserializer: IViewDeserializer<T>, options: IGridOptions = {}): SerializableGrid<T> {
|
||||
if (typeof json.orientation !== 'number') {
|
||||
throw new Error('Invalid JSON: \'orientation\' property must be a number.');
|
||||
@ -596,7 +551,7 @@ export class SerializableGrid<T extends ISerializableView> extends Grid<T> {
|
||||
};
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
override layout(width: number, height: number): void {
|
||||
super.layout(width, height);
|
||||
|
||||
if (this.initialLayoutContext) {
|
||||
|
@ -30,8 +30,7 @@
|
||||
}
|
||||
|
||||
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
|
||||
/* This is a strange rule but it avoids https://github.com/microsoft/vscode/issues/96795, just 100vw on its own caused the actual hover width to increase */
|
||||
min-width: calc(100% + 100vw);
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.monaco-hover p,
|
||||
|
@ -10,6 +10,10 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export const enum HoverPosition {
|
||||
LEFT, RIGHT, BELOW, ABOVE
|
||||
}
|
||||
|
||||
export class HoverWidget extends Disposable {
|
||||
|
||||
public readonly containerDomNode: HTMLElement;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
@ -15,7 +15,7 @@ export interface IHoverDelegateTarget extends IDisposable {
|
||||
export interface IHoverDelegateOptions {
|
||||
text: IMarkdownString | string;
|
||||
target: IHoverDelegateTarget | HTMLElement;
|
||||
anchorPosition?: AnchorPosition;
|
||||
hoverPosition?: HoverPosition;
|
||||
}
|
||||
|
||||
export interface IHoverDelegate {
|
||||
|
@ -11,12 +11,12 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/base/common/range';
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
|
||||
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { isFunction, isString } from 'vs/base/common/types';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
|
||||
export interface IIconLabelCreationOptions {
|
||||
supportHighlights?: boolean;
|
||||
@ -222,12 +222,12 @@ export class IconLabel extends Disposable {
|
||||
let isHovering = false;
|
||||
let tokenSource: CancellationTokenSource;
|
||||
let hoverDisposable: IDisposable | undefined;
|
||||
function mouseOver(this: HTMLElement, e: MouseEvent): any {
|
||||
function mouseOver(this: HTMLElement, e: MouseEvent): void {
|
||||
if (isHovering) {
|
||||
return;
|
||||
}
|
||||
tokenSource = new CancellationTokenSource();
|
||||
function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any {
|
||||
function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): void {
|
||||
const isMouseDown = e.type === dom.EventType.MOUSE_DOWN;
|
||||
if (isMouseDown) {
|
||||
hoverDisposable?.dispose();
|
||||
@ -245,7 +245,7 @@ export class IconLabel extends Disposable {
|
||||
const mouseDownDisposable = domEvent(htmlElement, dom.EventType.MOUSE_DOWN, true)(mouseLeaveOrDown.bind(htmlElement));
|
||||
isHovering = true;
|
||||
|
||||
function mouseMove(this: HTMLElement, e: MouseEvent): any {
|
||||
function mouseMove(this: HTMLElement, e: MouseEvent): void {
|
||||
mouseX = e.x;
|
||||
}
|
||||
const mouseMoveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_MOVE, true)(mouseMove.bind(htmlElement));
|
||||
@ -260,7 +260,7 @@ export class IconLabel extends Disposable {
|
||||
hoverOptions = {
|
||||
text: localize('iconLabel.loading', "Loading..."),
|
||||
target,
|
||||
anchorPosition: AnchorPosition.BELOW
|
||||
hoverPosition: HoverPosition.BELOW
|
||||
};
|
||||
hoverDisposable = IconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);
|
||||
|
||||
@ -269,7 +269,7 @@ export class IconLabel extends Disposable {
|
||||
hoverOptions = {
|
||||
text: resolvedTooltip,
|
||||
target,
|
||||
anchorPosition: AnchorPosition.BELOW
|
||||
hoverPosition: HoverPosition.BELOW
|
||||
};
|
||||
// awaiting the tooltip could take a while. Make sure we're still hovering.
|
||||
hoverDisposable = IconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);
|
||||
|
@ -610,7 +610,7 @@ export class InputBox extends Widget {
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this._hideMessage();
|
||||
|
||||
this.message = null;
|
||||
|
@ -11,13 +11,10 @@
|
||||
|
||||
.monaco-keybinding > .monaco-keybinding-key {
|
||||
display: inline-block;
|
||||
border: solid 1px rgba(204, 204, 204, 0.4);
|
||||
border-bottom-color: rgba(187, 187, 187, 0.4);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 rgba(187, 187, 187, 0.4);
|
||||
background-color: rgba(221, 221, 221, 0.4);
|
||||
vertical-align: middle;
|
||||
color: #555;
|
||||
font-size: 11px;
|
||||
padding: 3px 5px;
|
||||
margin: 0 2px;
|
||||
@ -31,19 +28,10 @@
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.hc-black .monaco-keybinding > .monaco-keybinding-key,
|
||||
.vs-dark .monaco-keybinding > .monaco-keybinding-key {
|
||||
background-color: rgba(128, 128, 128, 0.17);
|
||||
color: #ccc;
|
||||
border: solid 1px rgba(51, 51, 51, 0.6);
|
||||
border-bottom-color: rgba(68, 68, 68, 0.6);
|
||||
box-shadow: inset 0 -1px 0 rgba(68, 68, 68, 0.6);
|
||||
}
|
||||
|
||||
.monaco-keybinding > .monaco-keybinding-key-separator {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-keybinding > .monaco-keybinding-key-chord-separator {
|
||||
width: 6px;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import { ResolvedKeybinding, ResolvedKeybindingPart } from 'vs/base/common/keyCo
|
||||
import { UILabelProvider } from 'vs/base/common/keybindingLabels';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IThemable } from 'vs/base/common/styler';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@ -26,18 +28,44 @@ export interface Matches {
|
||||
chordPart: PartMatches;
|
||||
}
|
||||
|
||||
export interface KeybindingLabelOptions {
|
||||
renderUnboundKeybindings: boolean;
|
||||
export interface KeybindingLabelOptions extends IKeybindingLabelStyles {
|
||||
renderUnboundKeybindings?: boolean;
|
||||
}
|
||||
|
||||
export class KeybindingLabel {
|
||||
export interface IKeybindingLabelStyles {
|
||||
keybindingLabelBackground?: Color;
|
||||
keybindingLabelForeground?: Color;
|
||||
keybindingLabelBorder?: Color;
|
||||
keybindingLabelBottomBorder?: Color;
|
||||
keybindingLabelShadow?: Color;
|
||||
}
|
||||
|
||||
export class KeybindingLabel implements IThemable {
|
||||
|
||||
private domNode: HTMLElement;
|
||||
private options: KeybindingLabelOptions;
|
||||
|
||||
private readonly keyElements = new Set<HTMLSpanElement>();
|
||||
|
||||
private keybinding: ResolvedKeybinding | undefined;
|
||||
private matches: Matches | undefined;
|
||||
private didEverRender: boolean;
|
||||
|
||||
constructor(container: HTMLElement, private os: OperatingSystem, private options?: KeybindingLabelOptions) {
|
||||
private labelBackground: Color | undefined;
|
||||
private labelForeground: Color | undefined;
|
||||
private labelBorder: Color | undefined;
|
||||
private labelBottomBorder: Color | undefined;
|
||||
private labelShadow: Color | undefined;
|
||||
|
||||
constructor(container: HTMLElement, private os: OperatingSystem, options?: KeybindingLabelOptions) {
|
||||
this.options = options || Object.create(null);
|
||||
|
||||
this.labelBackground = this.options.keybindingLabelBackground;
|
||||
this.labelForeground = this.options.keybindingLabelForeground;
|
||||
this.labelBorder = this.options.keybindingLabelBorder;
|
||||
this.labelBottomBorder = this.options.keybindingLabelBottomBorder;
|
||||
this.labelShadow = this.options.keybindingLabelShadow;
|
||||
|
||||
this.domNode = dom.append(container, $('.monaco-keybinding'));
|
||||
this.didEverRender = false;
|
||||
container.appendChild(this.domNode);
|
||||
@ -58,7 +86,7 @@ export class KeybindingLabel {
|
||||
}
|
||||
|
||||
private render() {
|
||||
dom.clearNode(this.domNode);
|
||||
this.clear();
|
||||
|
||||
if (this.keybinding) {
|
||||
let [firstPart, chordPart] = this.keybinding.getParts();
|
||||
@ -74,9 +102,16 @@ export class KeybindingLabel {
|
||||
this.renderUnbound(this.domNode);
|
||||
}
|
||||
|
||||
this.applyStyles();
|
||||
|
||||
this.didEverRender = true;
|
||||
}
|
||||
|
||||
private clear(): void {
|
||||
dom.clearNode(this.domNode);
|
||||
this.keyElements.clear();
|
||||
}
|
||||
|
||||
private renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches | null) {
|
||||
const modifierLabels = UILabelProvider.modifierLabels[this.os];
|
||||
if (part.ctrlKey) {
|
||||
@ -98,14 +133,54 @@ export class KeybindingLabel {
|
||||
}
|
||||
|
||||
private renderKey(parent: HTMLElement, label: string, highlight: boolean, separator: string): void {
|
||||
dom.append(parent, $('span.monaco-keybinding-key' + (highlight ? '.highlight' : ''), undefined, label));
|
||||
dom.append(parent, this.createKeyElement(label, highlight ? '.highlight' : ''));
|
||||
if (separator) {
|
||||
dom.append(parent, $('span.monaco-keybinding-key-separator', undefined, separator));
|
||||
}
|
||||
}
|
||||
|
||||
private renderUnbound(parent: HTMLElement): void {
|
||||
dom.append(parent, $('span.monaco-keybinding-key', undefined, localize('unbound', "Unbound")));
|
||||
dom.append(parent, this.createKeyElement(localize('unbound', "Unbound")));
|
||||
}
|
||||
|
||||
private createKeyElement(label: string, extraClass = ''): HTMLElement {
|
||||
const keyElement = $('span.monaco-keybinding-key' + extraClass, undefined, label);
|
||||
this.keyElements.add(keyElement);
|
||||
|
||||
return keyElement;
|
||||
}
|
||||
|
||||
style(styles: IKeybindingLabelStyles): void {
|
||||
this.labelBackground = styles.keybindingLabelBackground;
|
||||
this.labelForeground = styles.keybindingLabelForeground;
|
||||
this.labelBorder = styles.keybindingLabelBorder;
|
||||
this.labelBottomBorder = styles.keybindingLabelBottomBorder;
|
||||
this.labelShadow = styles.keybindingLabelShadow;
|
||||
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
private applyStyles() {
|
||||
if (this.element) {
|
||||
for (const keyElement of this.keyElements) {
|
||||
if (this.labelBackground) {
|
||||
keyElement.style.backgroundColor = this.labelBackground?.toString();
|
||||
}
|
||||
if (this.labelBorder) {
|
||||
keyElement.style.borderColor = this.labelBorder.toString();
|
||||
}
|
||||
if (this.labelBottomBorder) {
|
||||
keyElement.style.borderBottomColor = this.labelBottomBorder.toString();
|
||||
}
|
||||
if (this.labelShadow) {
|
||||
keyElement.style.boxShadow = `inset 0 -1px 0 ${this.labelShadow}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.labelForeground) {
|
||||
this.element.style.color = this.labelForeground.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static areSame(a: Matches | undefined, b: Matches | undefined): boolean {
|
||||
|
@ -339,7 +339,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
container.appendChild(this.domNode);
|
||||
|
||||
this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
|
||||
domEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables);
|
||||
domEvent(this.rowsContainer, TouchEventType.Change)(e => this.onTouchChange(e as GestureEvent), this, this.disposables);
|
||||
|
||||
// Prevent the monaco-scrollable-element from scrolling
|
||||
// https://github.com/microsoft/vscode/issues/44181
|
||||
@ -362,6 +362,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
updateOptions(options: IListViewOptionsUpdate) {
|
||||
if (options.additionalScrollHeight !== undefined) {
|
||||
this.additionalScrollHeight = options.additionalScrollHeight;
|
||||
this.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });
|
||||
}
|
||||
|
||||
if (options.smoothScrolling !== undefined) {
|
||||
@ -407,6 +408,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
this.items[index].size = size;
|
||||
|
||||
this.render(lastRenderRange, Math.max(0, this.lastRenderTop + heightDiff), this.lastRenderHeight, undefined, undefined, true);
|
||||
this.setScrollTop(this.lastRenderTop);
|
||||
|
||||
this.eventuallyUpdateScrollDimensions();
|
||||
|
||||
@ -679,12 +681,12 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
if (this.supportDynamicHeights) {
|
||||
this._rerender(this.scrollTop, this.renderHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.horizontalScrolling) {
|
||||
this.scrollableElement.setScrollDimensions({
|
||||
width: typeof width === 'number' ? width : getContentWidth(this.domNode)
|
||||
});
|
||||
}
|
||||
if (this.horizontalScrolling) {
|
||||
this.scrollableElement.setScrollDimensions({
|
||||
width: typeof width === 'number' ? width : getContentWidth(this.domNode)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -898,7 +900,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
@memoize get onMouseOut(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mouseout'), e => this.toMouseEvent(e)); }
|
||||
@memoize get onContextMenu(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)); }
|
||||
@memoize get onTouchStart(): Event<IListTouchEvent<T>> { return Event.map(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)); }
|
||||
@memoize get onTap(): Event<IListGestureEvent<T>> { return Event.map(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e)); }
|
||||
@memoize get onTap(): Event<IListGestureEvent<T>> { return Event.map(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e as GestureEvent)); }
|
||||
|
||||
private toMouseEvent(browserEvent: MouseEvent): IListMouseEvent<T> {
|
||||
const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
|
||||
|
@ -188,7 +188,7 @@ class SelectionTrait<T> extends Trait<T> {
|
||||
super('selected');
|
||||
}
|
||||
|
||||
renderIndex(index: number, container: HTMLElement): void {
|
||||
override renderIndex(index: number, container: HTMLElement): void {
|
||||
super.renderIndex(index, container);
|
||||
|
||||
if (this.setAriaSelected) {
|
||||
@ -1635,13 +1635,13 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
|
||||
this.view.setScrollTop(m * clamp(relativeTop, 0, 1) + elementTop);
|
||||
} else {
|
||||
const viewItemBottom = elementTop + elementHeight;
|
||||
const wrapperBottom = scrollTop + this.view.renderHeight;
|
||||
const scrollBottom = scrollTop + this.view.renderHeight;
|
||||
|
||||
if (elementTop < scrollTop && viewItemBottom >= wrapperBottom) {
|
||||
if (elementTop < scrollTop && viewItemBottom >= scrollBottom) {
|
||||
// The element is already overflowing the viewport, no-op
|
||||
} else if (elementTop < scrollTop) {
|
||||
} else if (elementTop < scrollTop || (viewItemBottom >= scrollBottom && elementHeight >= this.view.renderHeight)) {
|
||||
this.view.setScrollTop(elementTop);
|
||||
} else if (viewItemBottom >= wrapperBottom) {
|
||||
} else if (viewItemBottom >= scrollBottom) {
|
||||
this.view.setScrollTop(viewItemBottom - this.view.renderHeight);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ export enum Direction {
|
||||
}
|
||||
|
||||
export interface IMenuOptions {
|
||||
context?: any;
|
||||
context?: unknown;
|
||||
actionViewItemProvider?: IActionViewItemProvider;
|
||||
actionRunner?: IActionRunner;
|
||||
getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined;
|
||||
@ -264,7 +264,7 @@ export class Menu extends ActionBar {
|
||||
}
|
||||
}
|
||||
|
||||
getContainer(): HTMLElement {
|
||||
override getContainer(): HTMLElement {
|
||||
return this.scrollableElement.getDomNode();
|
||||
}
|
||||
|
||||
@ -309,7 +309,7 @@ export class Menu extends ActionBar {
|
||||
}
|
||||
}
|
||||
|
||||
protected updateFocus(fromRight?: boolean): void {
|
||||
protected override updateFocus(fromRight?: boolean): void {
|
||||
super.updateFocus(fromRight, true);
|
||||
|
||||
if (typeof this.focusedItem !== 'undefined') {
|
||||
@ -385,7 +385,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
|
||||
public container: HTMLElement | undefined;
|
||||
|
||||
protected options: IMenuItemOptions;
|
||||
protected override options: IMenuItemOptions;
|
||||
protected item: HTMLElement | undefined;
|
||||
|
||||
private runOnceToEnableMouseUp: RunOnceScheduler;
|
||||
@ -465,7 +465,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
this._register(this.runOnceToEnableMouseUp);
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
|
||||
if (!this.element) {
|
||||
@ -504,12 +504,12 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
this.updateChecked();
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
override blur(): void {
|
||||
super.blur();
|
||||
this.applyStyle();
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
override focus(): void {
|
||||
super.focus();
|
||||
|
||||
if (this.item) {
|
||||
@ -526,7 +526,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateLabel(): void {
|
||||
override updateLabel(): void {
|
||||
if (!this.label) {
|
||||
return;
|
||||
}
|
||||
@ -579,7 +579,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateTooltip(): void {
|
||||
override updateTooltip(): void {
|
||||
let title: string | null = null;
|
||||
|
||||
if (this.getAction().tooltip) {
|
||||
@ -598,7 +598,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateClass(): void {
|
||||
override updateClass(): void {
|
||||
if (this.cssClass && this.item) {
|
||||
this.item.classList.remove(...this.cssClass.split(' '));
|
||||
}
|
||||
@ -614,7 +614,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateEnabled(): void {
|
||||
override updateEnabled(): void {
|
||||
if (this.getAction().enabled) {
|
||||
if (this.element) {
|
||||
this.element.classList.remove('disabled');
|
||||
@ -639,7 +639,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
updateChecked(): void {
|
||||
override updateChecked(): void {
|
||||
if (!this.item) {
|
||||
return;
|
||||
}
|
||||
@ -724,7 +724,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
}, 750);
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
override render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
|
||||
if (!this.element) {
|
||||
@ -783,7 +783,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
}));
|
||||
}
|
||||
|
||||
updateEnabled(): void {
|
||||
override updateEnabled(): void {
|
||||
// override on submenu entry
|
||||
// native menus do not observe enablement on sumbenus
|
||||
// we mimic that behavior
|
||||
@ -794,7 +794,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
this.createSubmenu(selectFirst);
|
||||
}
|
||||
|
||||
onClick(e: EventLike): void {
|
||||
override onClick(e: EventLike): void {
|
||||
// stop clicking from trying to run an action
|
||||
EventHelper.stop(e, true);
|
||||
|
||||
@ -925,7 +925,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
protected applyStyle(): void {
|
||||
protected override applyStyle(): void {
|
||||
super.applyStyle();
|
||||
|
||||
if (!this.menuStyle) {
|
||||
@ -944,7 +944,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.hideScheduler.dispose();
|
||||
|
@ -422,7 +422,7 @@ export class MenuBar extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.menuCache.forEach(menuBarMenu => {
|
||||
|
@ -211,7 +211,7 @@ export class Sash extends Disposable {
|
||||
this._register(domEvent(this.el, 'mouseleave')(() => Sash.onMouseLeave(this)));
|
||||
|
||||
this._register(Gesture.addTarget(this.el));
|
||||
this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this));
|
||||
this._register(domEvent(this.el, EventType.Start)(e => this.onTouchStart(e as GestureEvent), this));
|
||||
|
||||
if (typeof options.size === 'number') {
|
||||
this.size = options.size;
|
||||
@ -430,6 +430,10 @@ export class Sash extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
clearSashHoverState(): void {
|
||||
Sash.onMouseLeave(this);
|
||||
}
|
||||
|
||||
layout(): void {
|
||||
if (this.orientation === Orientation.VERTICAL) {
|
||||
const verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
|
||||
@ -484,7 +488,7 @@ export class Sash extends Disposable {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
this.el.remove();
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
this._domNode.appendChild(this._topShadowDomNode.domNode);
|
||||
|
||||
this._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));
|
||||
this._topLeftShadowDomNode.setClassName('shadow top-left-corner');
|
||||
this._topLeftShadowDomNode.setClassName('shadow');
|
||||
this._domNode.appendChild(this._topLeftShadowDomNode.domNode);
|
||||
} else {
|
||||
this._leftShadowDomNode = null;
|
||||
@ -239,7 +239,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
this._revealOnScroll = true;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this._mouseWheelToDispose = dispose(this._mouseWheelToDispose);
|
||||
super.dispose();
|
||||
}
|
||||
@ -484,9 +484,12 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
const enableTop = scrollState.scrollTop > 0;
|
||||
const enableLeft = scrollState.scrollLeft > 0;
|
||||
|
||||
this._leftShadowDomNode!.setClassName('shadow' + (enableLeft ? ' left' : ''));
|
||||
this._topShadowDomNode!.setClassName('shadow' + (enableTop ? ' top' : ''));
|
||||
this._topLeftShadowDomNode!.setClassName('shadow top-left-corner' + (enableTop ? ' top' : '') + (enableLeft ? ' left' : ''));
|
||||
const leftClassName = (enableLeft ? ' left' : '');
|
||||
const topClassName = (enableTop ? ' top' : '');
|
||||
const topLeftClassName = (enableLeft || enableTop ? ' top-left-corner' : '');
|
||||
this._leftShadowDomNode!.setClassName(`shadow${leftClassName}`);
|
||||
this._topShadowDomNode!.setClassName(`shadow${topClassName}`);
|
||||
this._topLeftShadowDomNode!.setClassName(`shadow${topLeftClassName}${topClassName}${leftClassName}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1046,7 +1046,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this.hideSelectDropDown(false);
|
||||
super.dispose();
|
||||
}
|
||||
|
@ -52,6 +52,14 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-item {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-label {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* TODO: actions should be part of the pane, but they aren't yet */
|
||||
.monaco-pane-view .pane:hover > .pane-header.expanded > .actions,
|
||||
.monaco-pane-view .pane:focus-within > .pane-header.expanded > .actions,
|
||||
@ -60,22 +68,6 @@
|
||||
display: initial;
|
||||
}
|
||||
|
||||
/* TODO: actions should be part of the pane, but they aren't yet */
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-label.icon,
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-label.codicon {
|
||||
width: 28px;
|
||||
height: 22px;
|
||||
background-size: 16px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: inherit;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {
|
||||
cursor: default;
|
||||
}
|
||||
|
@ -568,7 +568,7 @@ export class PaneView extends Disposable {
|
||||
}, 200);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.paneItems.forEach(i => i.disposable.dispose());
|
||||
|
@ -1022,7 +1022,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.viewItems.forEach(i => i.dispose());
|
||||
|
@ -3,6 +3,10 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-toolbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-toolbar .toolbar-toggle-more {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
|
@ -181,7 +181,7 @@ export class ToolBar extends Disposable {
|
||||
this.actionBar.clear();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.clear();
|
||||
super.dispose();
|
||||
}
|
||||
@ -202,7 +202,7 @@ class ToggleMenuAction extends Action {
|
||||
this.toggleDropdownMenu = toggleDropdownMenu;
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
override async run(): Promise<void> {
|
||||
this.toggleDropdownMenu();
|
||||
}
|
||||
|
||||
|
@ -29,11 +29,11 @@ import { treeItemExpandedIcon, treeFilterOnTypeOnIcon, treeFilterOnTypeOffIcon,
|
||||
|
||||
class TreeElementsDragAndDropData<T, TFilterData, TContext> extends ElementsDragAndDropData<T, TContext> {
|
||||
|
||||
set context(context: TContext | undefined) {
|
||||
override set context(context: TContext | undefined) {
|
||||
this.data.context = context;
|
||||
}
|
||||
|
||||
get context(): TContext | undefined {
|
||||
override get context(): TContext | undefined {
|
||||
return this.data.context;
|
||||
}
|
||||
|
||||
@ -1091,7 +1091,7 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
||||
super(list);
|
||||
}
|
||||
|
||||
protected onViewPointer(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
|
||||
protected override onViewPointer(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
@ -1141,7 +1141,7 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
||||
super.onViewPointer(e);
|
||||
}
|
||||
|
||||
protected onDoubleClick(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
|
||||
protected override onDoubleClick(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
|
||||
const onTwistie = (e.browserEvent.target as HTMLElement).classList.contains('monaco-tl-twistie');
|
||||
|
||||
if (onTwistie || !this.tree.expandOnDoubleClick) {
|
||||
@ -1175,11 +1175,11 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
super(user, container, virtualDelegate, renderers, options);
|
||||
}
|
||||
|
||||
protected createMouseController(options: ITreeNodeListOptions<T, TFilterData, TRef>): MouseController<ITreeNode<T, TFilterData>> {
|
||||
protected override createMouseController(options: ITreeNodeListOptions<T, TFilterData, TRef>): MouseController<ITreeNode<T, TFilterData>> {
|
||||
return new TreeNodeListMouseController(this, options.tree);
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, elements: ITreeNode<T, TFilterData>[] = []): void {
|
||||
override splice(start: number, deleteCount: number, elements: ITreeNode<T, TFilterData>[] = []): void {
|
||||
super.splice(start, deleteCount, elements);
|
||||
|
||||
if (elements.length === 0) {
|
||||
@ -1217,7 +1217,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
}
|
||||
}
|
||||
|
||||
setFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
|
||||
override setFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
|
||||
super.setFocus(indexes, browserEvent);
|
||||
|
||||
if (!fromAPI) {
|
||||
@ -1225,7 +1225,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
}
|
||||
}
|
||||
|
||||
setSelection(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
|
||||
override setSelection(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
|
||||
super.setSelection(indexes, browserEvent);
|
||||
|
||||
if (!fromAPI) {
|
||||
@ -1233,7 +1233,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
|
||||
}
|
||||
}
|
||||
|
||||
setAnchor(index: number | undefined, fromAPI = false): void {
|
||||
override setAnchor(index: number | undefined, fromAPI = false): void {
|
||||
super.setAnchor(index);
|
||||
|
||||
if (!fromAPI) {
|
||||
|
@ -157,11 +157,11 @@ function asTreeContextMenuEvent<TInput, T>(e: ITreeContextMenuEvent<IAsyncDataTr
|
||||
|
||||
class AsyncDataTreeElementsDragAndDropData<TInput, T, TContext> extends ElementsDragAndDropData<T, TContext> {
|
||||
|
||||
set context(context: TContext | undefined) {
|
||||
override set context(context: TContext | undefined) {
|
||||
this.data.context = context;
|
||||
}
|
||||
|
||||
get context(): TContext | undefined {
|
||||
override get context(): TContext | undefined {
|
||||
return this.data.context;
|
||||
}
|
||||
|
||||
@ -1131,7 +1131,7 @@ export interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeO
|
||||
|
||||
export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends AsyncDataTree<TInput, T, TFilterData> {
|
||||
|
||||
protected readonly tree!: CompressibleObjectTree<IAsyncDataTreeNode<TInput, T>, TFilterData>;
|
||||
protected override readonly tree!: CompressibleObjectTree<IAsyncDataTreeNode<TInput, T>, TFilterData>;
|
||||
protected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper<TInput, T, TFilterData> = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node));
|
||||
private filter?: ITreeFilter<T, TFilterData>;
|
||||
|
||||
@ -1148,7 +1148,7 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
|
||||
this.filter = options.filter;
|
||||
}
|
||||
|
||||
protected createTree(
|
||||
protected override createTree(
|
||||
user: string,
|
||||
container: HTMLElement,
|
||||
delegate: IListVirtualDelegate<T>,
|
||||
@ -1162,18 +1162,18 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
|
||||
return new CompressibleObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);
|
||||
}
|
||||
|
||||
protected asTreeElement(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): ICompressedTreeElement<IAsyncDataTreeNode<TInput, T>> {
|
||||
protected override asTreeElement(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): ICompressedTreeElement<IAsyncDataTreeNode<TInput, T>> {
|
||||
return {
|
||||
incompressible: this.compressionDelegate.isIncompressible(node.element as T),
|
||||
...super.asTreeElement(node, viewStateContext)
|
||||
};
|
||||
}
|
||||
|
||||
updateOptions(options: ICompressibleAsyncDataTreeOptionsUpdate = {}): void {
|
||||
override updateOptions(options: ICompressibleAsyncDataTreeOptionsUpdate = {}): void {
|
||||
this.tree.updateOptions(options);
|
||||
}
|
||||
|
||||
getViewState(): IAsyncDataTreeViewState {
|
||||
override getViewState(): IAsyncDataTreeViewState {
|
||||
if (!this.identityProvider) {
|
||||
throw new TreeError(this.user, 'Can\'t get tree view state without an identity provider');
|
||||
}
|
||||
@ -1201,7 +1201,7 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
|
||||
return { focus, selection, expanded, scrollTop: this.scrollTop };
|
||||
}
|
||||
|
||||
protected render(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): void {
|
||||
protected override render(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): void {
|
||||
if (!this.identityProvider) {
|
||||
return super.render(node, viewStateContext);
|
||||
}
|
||||
@ -1277,7 +1277,7 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
|
||||
// For compressed async data trees, `TreeVisibility.Recurse` doesn't currently work
|
||||
// and we have to filter everything beforehand
|
||||
// Related to #85193 and #85835
|
||||
protected processChildren(children: Iterable<T>): Iterable<T> {
|
||||
protected override processChildren(children: Iterable<T>): Iterable<T> {
|
||||
if (this.filter) {
|
||||
children = Iterable.filter(children, e => {
|
||||
const result = this.filter!.filter(e, TreeVisibility.Visible);
|
||||
|
@ -23,7 +23,7 @@ export interface IDataTreeViewState {
|
||||
|
||||
export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | null, TFilterData, T | null> {
|
||||
|
||||
protected model!: ObjectTreeModel<T, TFilterData>;
|
||||
protected override model!: ObjectTreeModel<T, TFilterData>;
|
||||
private input: TInput | undefined;
|
||||
|
||||
private identityProvider: IIdentityProvider<T> | undefined;
|
||||
|
@ -14,7 +14,7 @@ export interface IIndexTreeOptions<T, TFilterData = void> extends IAbstractTreeO
|
||||
|
||||
export class IndexTree<T, TFilterData = void> extends AbstractTree<T, TFilterData, number[]> {
|
||||
|
||||
protected model!: IndexTreeModel<T, TFilterData>;
|
||||
protected override model!: IndexTreeModel<T, TFilterData>;
|
||||
|
||||
constructor(
|
||||
user: string,
|
||||
|
@ -38,9 +38,9 @@ export interface IObjectTreeSetChildrenOptions<T> {
|
||||
|
||||
export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends AbstractTree<T | null, TFilterData, T | null> {
|
||||
|
||||
protected model!: IObjectTreeModel<T, TFilterData>;
|
||||
protected override model!: IObjectTreeModel<T, TFilterData>;
|
||||
|
||||
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T | null, TFilterData>> { return this.model.onDidChangeCollapseState; }
|
||||
override get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T | null, TFilterData>> { return this.model.onDidChangeCollapseState; }
|
||||
|
||||
constructor(
|
||||
user: string,
|
||||
@ -194,7 +194,7 @@ export interface ICompressibleObjectTreeOptionsUpdate extends IAbstractTreeOptio
|
||||
|
||||
export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> implements ICompressedTreeNodeProvider<T, TFilterData> {
|
||||
|
||||
protected model!: CompressibleObjectTreeModel<T, TFilterData>;
|
||||
protected override model!: CompressibleObjectTreeModel<T, TFilterData>;
|
||||
|
||||
constructor(
|
||||
user: string,
|
||||
@ -208,15 +208,15 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
|
||||
super(user, container, delegate, compressibleRenderers, asObjectTreeOptions<T, TFilterData>(compressedTreeNodeProvider, options));
|
||||
}
|
||||
|
||||
setChildren(element: T | null, children: Iterable<ICompressedTreeElement<T>> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions<T>): void {
|
||||
override setChildren(element: T | null, children: Iterable<ICompressedTreeElement<T>> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions<T>): void {
|
||||
this.model.setChildren(element, children, options);
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: ICompressibleObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
protected override createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: ICompressibleObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
return new CompressibleObjectTreeModel(user, view, options);
|
||||
}
|
||||
|
||||
updateOptions(optionsUpdate: ICompressibleObjectTreeOptionsUpdate = {}): void {
|
||||
override updateOptions(optionsUpdate: ICompressibleObjectTreeOptionsUpdate = {}): void {
|
||||
super.updateOptions(optionsUpdate);
|
||||
|
||||
if (typeof optionsUpdate.compressionEnabled !== 'undefined') {
|
||||
|
@ -13,11 +13,9 @@ export class CollapseAllAction<TInput, T, TFilterData = void> extends Action {
|
||||
super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'collapse-all', enabled);
|
||||
}
|
||||
|
||||
async run(): Promise<any> {
|
||||
override async run(): Promise<any> {
|
||||
this.viewer.collapseAll();
|
||||
this.viewer.setSelection([]);
|
||||
this.viewer.setFocus([]);
|
||||
this.viewer.domFocus();
|
||||
this.viewer.focusFirst();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
export interface ITelemetryData {
|
||||
readonly from?: string;
|
||||
readonly target?: string;
|
||||
[key: string]: any;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export type WorkbenchActionExecutedClassification = {
|
||||
@ -30,13 +30,14 @@ export interface IAction extends IDisposable {
|
||||
class: string | undefined;
|
||||
enabled: boolean;
|
||||
checked: boolean;
|
||||
run(event?: any): Promise<any>;
|
||||
run(event?: unknown): Promise<unknown>;
|
||||
}
|
||||
|
||||
export interface IActionRunner extends IDisposable {
|
||||
run(action: IAction, context?: any): Promise<any>;
|
||||
readonly onDidRun: Event<IRunEvent>;
|
||||
readonly onBeforeRun: Event<IRunEvent>;
|
||||
|
||||
run(action: IAction, context?: unknown): Promise<unknown>;
|
||||
}
|
||||
|
||||
export interface IActionChangeEvent {
|
||||
@ -58,9 +59,9 @@ export class Action extends Disposable implements IAction {
|
||||
protected _cssClass: string | undefined;
|
||||
protected _enabled: boolean = true;
|
||||
protected _checked: boolean = false;
|
||||
protected readonly _actionCallback?: (event?: any) => Promise<any>;
|
||||
protected readonly _actionCallback?: (event?: unknown) => Promise<unknown>;
|
||||
|
||||
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise<any>) {
|
||||
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: unknown) => Promise<unknown>) {
|
||||
super();
|
||||
this._id = id;
|
||||
this._label = label;
|
||||
@ -148,19 +149,16 @@ export class Action extends Disposable implements IAction {
|
||||
}
|
||||
}
|
||||
|
||||
run(event?: any, _data?: ITelemetryData): Promise<any> {
|
||||
async run(event?: unknown, data?: ITelemetryData): Promise<void> {
|
||||
if (this._actionCallback) {
|
||||
return this._actionCallback(event);
|
||||
await this._actionCallback(event);
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IRunEvent {
|
||||
readonly action: IAction;
|
||||
readonly result?: any;
|
||||
readonly error?: any;
|
||||
readonly error?: Error;
|
||||
}
|
||||
|
||||
export class ActionRunner extends Disposable implements IActionRunner {
|
||||
@ -171,24 +169,25 @@ export class ActionRunner extends Disposable implements IActionRunner {
|
||||
private _onDidRun = this._register(new Emitter<IRunEvent>());
|
||||
readonly onDidRun = this._onDidRun.event;
|
||||
|
||||
async run(action: IAction, context?: any): Promise<any> {
|
||||
async run(action: IAction, context?: unknown): Promise<void> {
|
||||
if (!action.enabled) {
|
||||
return Promise.resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this._onBeforeRun.fire({ action: action });
|
||||
this._onBeforeRun.fire({ action });
|
||||
|
||||
let error: Error | undefined = undefined;
|
||||
try {
|
||||
const result = await this.runAction(action, context);
|
||||
this._onDidRun.fire({ action: action, result: result });
|
||||
} catch (error) {
|
||||
this._onDidRun.fire({ action: action, error: error });
|
||||
await this.runAction(action, context);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
this._onDidRun.fire({ action, error });
|
||||
}
|
||||
|
||||
protected runAction(action: IAction, context?: any): Promise<any> {
|
||||
const res = context ? action.run(context) : action.run();
|
||||
return Promise.resolve(res);
|
||||
protected async runAction(action: IAction, context?: unknown): Promise<void> {
|
||||
await action.run(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,6 +197,7 @@ export class Separator extends Action {
|
||||
|
||||
constructor(label?: string) {
|
||||
super(Separator.ID, label, label ? 'separator text' : 'separator');
|
||||
|
||||
this.checked = false;
|
||||
this.enabled = false;
|
||||
}
|
||||
@ -213,6 +213,7 @@ export class SubmenuAction implements IAction {
|
||||
readonly checked: boolean = false;
|
||||
|
||||
private readonly _actions: readonly IAction[];
|
||||
get actions(): readonly IAction[] { return this._actions; }
|
||||
|
||||
constructor(id: string, label: string, actions: readonly IAction[], cssClass?: string) {
|
||||
this.id = id;
|
||||
@ -227,15 +228,13 @@ export class SubmenuAction implements IAction {
|
||||
// to bridge into the rendering world.
|
||||
}
|
||||
|
||||
get actions(): readonly IAction[] {
|
||||
return this._actions;
|
||||
}
|
||||
|
||||
async run(): Promise<any> { }
|
||||
async run(): Promise<void> { }
|
||||
}
|
||||
|
||||
export class EmptySubmenuAction extends Action {
|
||||
|
||||
static readonly ID = 'vs.actions.empty';
|
||||
|
||||
constructor() {
|
||||
super(EmptySubmenuAction.ID, nls.localize('submenu.empty', '(empty)'), undefined, false);
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ export class AutoOpenBarrier extends Barrier {
|
||||
this._timeout = setTimeout(() => this.open(), autoOpenTimeMs);
|
||||
}
|
||||
|
||||
open(): void {
|
||||
override open(): void {
|
||||
clearTimeout(this._timeout);
|
||||
super.open();
|
||||
}
|
||||
@ -772,7 +772,7 @@ export class RunOnceWorker<T> extends RunOnceScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
protected doRun(): void {
|
||||
protected override doRun(): void {
|
||||
const units = this.units;
|
||||
this.units = [];
|
||||
|
||||
@ -781,7 +781,7 @@ export class RunOnceWorker<T> extends RunOnceScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.units = [];
|
||||
|
||||
super.dispose();
|
||||
@ -942,7 +942,7 @@ export class TaskSequentializer {
|
||||
}
|
||||
|
||||
setPending(taskId: number, promise: Promise<void>, onCancel?: () => void,): Promise<void> {
|
||||
this._pending = { taskId: taskId, cancel: () => onCancel?.(), promise };
|
||||
this._pending = { taskId, cancel: () => onCancel?.(), promise };
|
||||
|
||||
promise.then(() => this.donePending(taskId), () => this.donePending(taskId));
|
||||
|
||||
@ -1179,7 +1179,7 @@ export namespace Promises {
|
||||
* Interface of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
||||
*/
|
||||
interface PromiseWithAllSettled<T> {
|
||||
allSettled<T>(promises: Promise<T>[]): Promise<ReadonlyArray<IResolvedPromise<T> | IRejectedPromise>>;
|
||||
allSettled<T>(promises: Promise<T>[]): Promise<readonly (IResolvedPromise<T> | IRejectedPromise)[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1188,7 +1188,7 @@ export namespace Promises {
|
||||
* in the order of the original passed in promises array.
|
||||
* See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
||||
*/
|
||||
export async function allSettled<T>(promises: Promise<T>[]): Promise<ReadonlyArray<IResolvedPromise<T> | IRejectedPromise>> {
|
||||
export async function allSettled<T>(promises: Promise<T>[]): Promise<readonly (IResolvedPromise<T> | IRejectedPromise)[]> {
|
||||
if (typeof (Promise as unknown as PromiseWithAllSettled<T>).allSettled === 'function') {
|
||||
return allSettledNative(promises); // in some environments we can benefit from native implementation
|
||||
}
|
||||
@ -1196,11 +1196,11 @@ export namespace Promises {
|
||||
return allSettledShim(promises);
|
||||
}
|
||||
|
||||
async function allSettledNative<T>(promises: Promise<T>[]): Promise<ReadonlyArray<IResolvedPromise<T> | IRejectedPromise>> {
|
||||
async function allSettledNative<T>(promises: Promise<T>[]): Promise<readonly (IResolvedPromise<T> | IRejectedPromise)[]> {
|
||||
return (Promise as unknown as PromiseWithAllSettled<T>).allSettled(promises);
|
||||
}
|
||||
|
||||
async function allSettledShim<T>(promises: Promise<T>[]): Promise<ReadonlyArray<IResolvedPromise<T> | IRejectedPromise>> {
|
||||
async function allSettledShim<T>(promises: Promise<T>[]): Promise<readonly (IResolvedPromise<T> | IRejectedPromise)[]> {
|
||||
return Promise.all(promises.map(promise => (promise.then(value => {
|
||||
const fulfilled: IResolvedPromise<T> = { status: 'fulfilled', value };
|
||||
|
||||
|
@ -235,3 +235,11 @@ export function streamToBufferReadableStream(stream: streams.ReadableStreamEvent
|
||||
export function newWriteableBufferStream(options?: streams.WriteableStreamOptions): streams.WriteableStream<VSBuffer> {
|
||||
return streams.newWriteableStream<VSBuffer>(chunks => VSBuffer.concat(chunks), options);
|
||||
}
|
||||
|
||||
export function prefixedBufferReadable(prefix: VSBuffer, readable: VSBufferReadable): VSBufferReadable {
|
||||
return streams.prefixedReadable(prefix, readable, chunks => VSBuffer.concat(chunks));
|
||||
}
|
||||
|
||||
export function prefixedBufferStream(prefix: VSBuffer, stream: VSBufferReadableStream): VSBufferReadableStream {
|
||||
return streams.prefixedStream(prefix, stream, chunks => VSBuffer.concat(chunks));
|
||||
}
|
||||
|
@ -49,6 +49,16 @@ export function registerCodicon(id: string, def: Codicon): Codicon {
|
||||
return new Codicon(id, def);
|
||||
}
|
||||
|
||||
// Selects all codicon names encapsulated in the `$()` syntax and wraps the
|
||||
// results with spaces so that screen readers can read the text better.
|
||||
export function getCodiconAriaLabel(text: string | undefined) {
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return text.replace(/\$\((.*?)\)/g, (_match, codiconName) => ` ${codiconName} `).trim();
|
||||
}
|
||||
|
||||
export class Codicon implements CSSIcon {
|
||||
constructor(public readonly id: string, public readonly definition: Codicon | IconDefinition, public description?: string) {
|
||||
_registry.add(this);
|
||||
@ -131,7 +141,6 @@ export namespace Codicon {
|
||||
export const tagAdd = new Codicon('tag-add', { fontCharacter: '\\ea66' });
|
||||
export const tagRemove = new Codicon('tag-remove', { fontCharacter: '\\ea66' });
|
||||
export const person = new Codicon('person', { fontCharacter: '\\ea67' });
|
||||
export const personAdd = new Codicon('person-add', { fontCharacter: '\\ea67' });
|
||||
export const personFollow = new Codicon('person-follow', { fontCharacter: '\\ea67' });
|
||||
export const personOutline = new Codicon('person-outline', { fontCharacter: '\\ea67' });
|
||||
export const personFilled = new Codicon('person-filled', { fontCharacter: '\\ea67' });
|
||||
@ -550,7 +559,20 @@ export namespace Codicon {
|
||||
export const debugRerun = new Codicon('debug-rerun', { fontCharacter: '\\ebc0' });
|
||||
export const workspaceTrusted = new Codicon('workspace-trusted', { fontCharacter: '\\ebc1' });
|
||||
export const workspaceUntrusted = new Codicon('workspace-untrusted', { fontCharacter: '\\ebc2' });
|
||||
export const workspaceUnknown = new Codicon('workspace-unknown', { fontCharacter: '\\ebc3' });
|
||||
export const workspaceUnspecified = new Codicon('workspace-unspecified', { fontCharacter: '\\ebc3' });
|
||||
export const terminalCmd = new Codicon('terminal-cmd', { fontCharacter: '\\ebc4' });
|
||||
export const terminalDebian = new Codicon('terminal-debian', { fontCharacter: '\\ebc5' });
|
||||
export const terminalLinux = new Codicon('terminal-linux', { fontCharacter: '\\ebc6' });
|
||||
export const terminalPowershell = new Codicon('terminal-powershell', { fontCharacter: '\\ebc7' });
|
||||
export const terminalTmux = new Codicon('terminal-tmux', { fontCharacter: '\\ebc8' });
|
||||
export const terminalUbuntu = new Codicon('terminal-ubuntu', { fontCharacter: '\\ebc9' });
|
||||
export const terminalBash = new Codicon('terminal-bash', { fontCharacter: '\\ebca' });
|
||||
export const arrowSwap = new Codicon('arrow-swap', { fontCharacter: '\\ebcb' });
|
||||
export const copy = new Codicon('copy', { fontCharacter: '\\ebcc' });
|
||||
export const personAdd = new Codicon('person-add', { fontCharacter: '\\ebcd' });
|
||||
export const filterFilled = new Codicon('filter-filled', { fontCharacter: '\\ebce' });
|
||||
export const wand = new Codicon('wand', { fontCharacter: '\\ebcf' });
|
||||
export const debugLineByLine = new Codicon('debug-line-by-line', { fontCharacter: '\\ebd0' });
|
||||
|
||||
export const dropDownButton = new Codicon('drop-down-button', Codicon.chevronDown.definition);
|
||||
}
|
||||
|
@ -66,6 +66,24 @@ export function groupBy<T>(data: T[], groupFn: (element: T) => string): IStringD
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups the collection into a dictionary based on the provided
|
||||
* group function.
|
||||
*/
|
||||
export function groupByNumber<T>(data: T[], groupFn: (element: T) => number): Map<number, T[]> {
|
||||
const result = new Map<number, T[]>();
|
||||
for (const element of data) {
|
||||
const key = groupFn(element);
|
||||
let target = result.get(key);
|
||||
if (!target) {
|
||||
target = [];
|
||||
result.set(key, target);
|
||||
}
|
||||
target.push(element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function fromMap<T>(original: Map<string, T>): IStringDictionary<T> {
|
||||
const result: IStringDictionary<T> = Object.create(null);
|
||||
if (original) {
|
||||
|
@ -229,11 +229,11 @@ export class ExpectedError extends Error {
|
||||
}
|
||||
|
||||
export interface IErrorOptions {
|
||||
actions?: ReadonlyArray<IAction>;
|
||||
actions?: readonly IAction[];
|
||||
}
|
||||
|
||||
export interface IErrorWithActions {
|
||||
actions?: ReadonlyArray<IAction>;
|
||||
actions?: readonly IAction[];
|
||||
}
|
||||
|
||||
export function isErrorWithActions(obj: unknown): obj is IErrorWithActions {
|
||||
|
@ -674,7 +674,7 @@ export class PauseableEmitter<T> extends Emitter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fire(event: T): void {
|
||||
override fire(event: T): void {
|
||||
if (this._listeners) {
|
||||
if (this._isPaused !== 0) {
|
||||
this._eventQueue.push(event);
|
||||
|
@ -12,6 +12,8 @@ import { illegalArgument } from 'vs/base/common/errors';
|
||||
* But these are "more general", as they should work across browsers & OS`s.
|
||||
*/
|
||||
export const enum KeyCode {
|
||||
DependsOnKbLayout = -1,
|
||||
|
||||
/**
|
||||
* Placed first to cover the 0 value of the enum.
|
||||
*/
|
||||
|
@ -887,7 +887,7 @@ export class LinkedMap<K, V> implements Map<K, V> {
|
||||
this._tail = undefined;
|
||||
}
|
||||
else if (item === this._head) {
|
||||
// This can only happend if size === 1 which is handle
|
||||
// This can only happen if size === 1 which is handled
|
||||
// by the case above.
|
||||
if (!item.next) {
|
||||
throw new Error('Invalid list');
|
||||
@ -896,7 +896,7 @@ export class LinkedMap<K, V> implements Map<K, V> {
|
||||
this._head = item.next;
|
||||
}
|
||||
else if (item === this._tail) {
|
||||
// This can only happend if size === 1 which is handle
|
||||
// This can only happen if size === 1 which is handled
|
||||
// by the case above.
|
||||
if (!item.previous) {
|
||||
throw new Error('Invalid list');
|
||||
@ -1028,7 +1028,7 @@ export class LRUCache<K, V> extends LinkedMap<K, V> {
|
||||
this.checkTrim();
|
||||
}
|
||||
|
||||
get(key: K, touch: Touch = Touch.AsNew): V | undefined {
|
||||
override get(key: K, touch: Touch = Touch.AsNew): V | undefined {
|
||||
return super.get(key, touch);
|
||||
}
|
||||
|
||||
@ -1036,7 +1036,7 @@ export class LRUCache<K, V> extends LinkedMap<K, V> {
|
||||
return super.get(key, Touch.None);
|
||||
}
|
||||
|
||||
set(key: K, value: V): this {
|
||||
override set(key: K, value: V): this {
|
||||
super.set(key, value, Touch.AsNew);
|
||||
this.checkTrim();
|
||||
return this;
|
||||
@ -1048,3 +1048,47 @@ export class LRUCache<K, V> extends LinkedMap<K, V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the map in type that only implements readonly properties. Useful
|
||||
* in the extension host to prevent the consumer from making any mutations.
|
||||
*/
|
||||
export class ReadonlyMapView<K, V> implements ReadonlyMap<K, V>{
|
||||
readonly #source: ReadonlyMap<K, V>;
|
||||
|
||||
public get size() {
|
||||
return this.#source.size;
|
||||
}
|
||||
|
||||
constructor(source: ReadonlyMap<K, V>) {
|
||||
this.#source = source;
|
||||
}
|
||||
|
||||
forEach(callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void, thisArg?: any): void {
|
||||
this.#source.forEach(callbackfn, thisArg);
|
||||
}
|
||||
|
||||
get(key: K): V | undefined {
|
||||
return this.#source.get(key);
|
||||
}
|
||||
|
||||
has(key: K): boolean {
|
||||
return this.#source.has(key);
|
||||
}
|
||||
|
||||
entries(): IterableIterator<[K, V]> {
|
||||
return this.#source.entries();
|
||||
}
|
||||
|
||||
keys(): IterableIterator<K> {
|
||||
return this.#source.keys();
|
||||
}
|
||||
|
||||
values(): IterableIterator<V> {
|
||||
return this.#source.values();
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<[K, V]> {
|
||||
return this.#source.entries();
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ export namespace Schemas {
|
||||
|
||||
export const vscodeWorkspaceTrust = 'vscode-workspace-trust';
|
||||
|
||||
export const vscodeTerminal = 'vscode-terminal';
|
||||
|
||||
export const webviewPanel = 'webview-panel';
|
||||
|
||||
/**
|
||||
@ -73,11 +75,6 @@ export namespace Schemas {
|
||||
*/
|
||||
export const vscodeWebview = 'vscode-webview';
|
||||
|
||||
/**
|
||||
* Scheme used for loading resources inside of webviews.
|
||||
*/
|
||||
export const vscodeWebviewResource = 'vscode-webview-resource';
|
||||
|
||||
/**
|
||||
* Scheme used for extension pages
|
||||
*/
|
||||
@ -88,6 +85,11 @@ export namespace Schemas {
|
||||
* files with our custom protocol handler (desktop only).
|
||||
*/
|
||||
export const vscodeFileResource = 'vscode-file';
|
||||
|
||||
/**
|
||||
* Scheme used for temporary resources
|
||||
*/
|
||||
export const tmp = 'tmp';
|
||||
}
|
||||
|
||||
class RemoteAuthoritiesImpl {
|
||||
@ -162,7 +164,7 @@ class FileAccessImpl {
|
||||
}
|
||||
|
||||
// Only convert the URI if we are in a native context and it has `file:` scheme
|
||||
// and we have explicitly enabled the conversion (sandbox, or ENABLE_VSCODE_BROWSER_CODE_LOADING)
|
||||
// and we have explicitly enabled the conversion (sandbox, or VSCODE_BROWSER_CODE_LOADING)
|
||||
if (platform.isNative && (__forceCodeFileUri || platform.isPreferringBrowserCodeLoad) && uri.scheme === Schemas.file) {
|
||||
return uri.with({
|
||||
scheme: Schemas.vscodeFileResource,
|
||||
|
@ -24,7 +24,7 @@ interface NLSConfig {
|
||||
}
|
||||
|
||||
export interface IProcessEnvironment {
|
||||
[key: string]: string;
|
||||
[key: string]: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,12 +53,12 @@ declare const self: unknown;
|
||||
export const globals: any = (typeof self === 'object' ? self : typeof global === 'object' ? global : {});
|
||||
|
||||
let nodeProcess: INodeProcess | undefined = undefined;
|
||||
if (typeof process !== 'undefined') {
|
||||
// Native environment (non-sandboxed)
|
||||
nodeProcess = process;
|
||||
} else if (typeof globals.vscode !== 'undefined') {
|
||||
if (typeof globals.vscode !== 'undefined') {
|
||||
// Native environment (sandboxed)
|
||||
nodeProcess = globals.vscode.process;
|
||||
} else if (typeof process !== 'undefined') {
|
||||
// Native environment (non-sandboxed)
|
||||
nodeProcess = process;
|
||||
}
|
||||
|
||||
const isElectronRenderer = typeof nodeProcess?.versions?.electron === 'string' && nodeProcess.type === 'renderer';
|
||||
@ -71,7 +71,7 @@ export const browserCodeLoadingCacheStrategy: 'none' | 'code' | 'bypassHeatCheck
|
||||
}
|
||||
|
||||
// Otherwise, only enabled conditionally
|
||||
const env = nodeProcess?.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'];
|
||||
const env = nodeProcess?.env['VSCODE_BROWSER_CODE_LOADING'];
|
||||
if (typeof env === 'string') {
|
||||
if (env === 'none' || env === 'code' || env === 'bypassHeatCheck' || env === 'bypassHeatCheckAndEagerCompile') {
|
||||
return env;
|
||||
|
@ -6,20 +6,10 @@
|
||||
import { isWindows, isMacintosh, setImmediate, globals, INodeProcess } from 'vs/base/common/platform';
|
||||
|
||||
let safeProcess: INodeProcess & { nextTick: (callback: (...args: any[]) => void) => void; };
|
||||
|
||||
// Native node.js environment
|
||||
declare const process: INodeProcess;
|
||||
if (typeof process !== 'undefined') {
|
||||
safeProcess = {
|
||||
get platform() { return process.platform; },
|
||||
get env() { return process.env; },
|
||||
cwd() { return process.env['VSCODE_CWD'] || process.cwd(); },
|
||||
nextTick(callback: (...args: any[]) => void): void { return process.nextTick!(callback); }
|
||||
};
|
||||
}
|
||||
|
||||
// Native sandbox environment
|
||||
else if (typeof globals.vscode !== 'undefined') {
|
||||
if (typeof globals.vscode !== 'undefined') {
|
||||
const sandboxProcess: INodeProcess = globals.vscode.process;
|
||||
safeProcess = {
|
||||
get platform() { return sandboxProcess.platform; },
|
||||
@ -29,6 +19,16 @@ else if (typeof globals.vscode !== 'undefined') {
|
||||
};
|
||||
}
|
||||
|
||||
// Native node.js environment
|
||||
else if (typeof process !== 'undefined') {
|
||||
safeProcess = {
|
||||
get platform() { return process.platform; },
|
||||
get env() { return process.env; },
|
||||
cwd() { return process.env['VSCODE_CWD'] || process.cwd(); },
|
||||
nextTick(callback: (...args: any[]) => void): void { return process.nextTick!(callback); }
|
||||
};
|
||||
}
|
||||
|
||||
// Web environment
|
||||
else {
|
||||
safeProcess = {
|
||||
|
168
lib/vscode/src/vs/base/common/product.ts
Normal file
168
lib/vscode/src/vs/base/common/product.ts
Normal file
@ -0,0 +1,168 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
|
||||
export interface IBuiltInExtension {
|
||||
readonly name: string;
|
||||
readonly version: string;
|
||||
readonly repo: string;
|
||||
readonly metadata: any;
|
||||
}
|
||||
|
||||
export type ConfigurationSyncStore = {
|
||||
url: string,
|
||||
insidersUrl: string,
|
||||
stableUrl: string,
|
||||
canSwitch: boolean,
|
||||
authenticationProviders: IStringDictionary<{ scopes: string[] }>
|
||||
};
|
||||
|
||||
export type ExtensionUntrustedWorkspaceSupport = {
|
||||
readonly default?: boolean | 'limited',
|
||||
readonly override?: boolean | 'limited'
|
||||
};
|
||||
|
||||
export interface IProductConfiguration {
|
||||
readonly version: string;
|
||||
readonly date?: string;
|
||||
readonly quality?: string;
|
||||
readonly commit?: string;
|
||||
|
||||
readonly nameShort: string;
|
||||
readonly nameLong: string;
|
||||
|
||||
readonly win32AppUserModelId?: string;
|
||||
readonly win32MutexName?: string;
|
||||
readonly applicationName: string;
|
||||
|
||||
readonly urlProtocol: string;
|
||||
readonly dataFolderName: string; // location for extensions (e.g. ~/.vscode-insiders)
|
||||
|
||||
readonly builtInExtensions?: IBuiltInExtension[];
|
||||
|
||||
readonly downloadUrl?: string;
|
||||
readonly updateUrl?: string;
|
||||
readonly webEndpointUrl?: string;
|
||||
readonly target?: string;
|
||||
|
||||
readonly settingsSearchBuildId?: number;
|
||||
readonly settingsSearchUrl?: string;
|
||||
|
||||
readonly tasConfig?: {
|
||||
endpoint: string;
|
||||
telemetryEventName: string;
|
||||
featuresTelemetryPropertyName: string;
|
||||
assignmentContextTelemetryPropertyName: string;
|
||||
};
|
||||
|
||||
readonly experimentsUrl?: string;
|
||||
|
||||
readonly extensionsGallery?: {
|
||||
readonly serviceUrl: string;
|
||||
readonly itemUrl: string;
|
||||
readonly controlUrl: string;
|
||||
readonly recommendationsUrl: string;
|
||||
};
|
||||
|
||||
readonly extensionTips?: { [id: string]: string; };
|
||||
readonly extensionImportantTips?: IStringDictionary<ImportantExtensionTip>;
|
||||
readonly configBasedExtensionTips?: { [id: string]: IConfigBasedExtensionTip; };
|
||||
readonly exeBasedExtensionTips?: { [id: string]: IExeBasedExtensionTip; };
|
||||
readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; };
|
||||
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
|
||||
readonly keymapExtensionTips?: readonly string[];
|
||||
readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; };
|
||||
|
||||
readonly crashReporter?: {
|
||||
readonly companyName: string;
|
||||
readonly productName: string;
|
||||
};
|
||||
|
||||
readonly enableTelemetry?: boolean;
|
||||
readonly aiConfig?: {
|
||||
readonly asimovKey: string;
|
||||
};
|
||||
|
||||
readonly sendASmile?: {
|
||||
readonly reportIssueUrl: string,
|
||||
readonly requestFeatureUrl: string
|
||||
};
|
||||
|
||||
readonly documentationUrl?: string;
|
||||
readonly releaseNotesUrl?: string;
|
||||
readonly keyboardShortcutsUrlMac?: string;
|
||||
readonly keyboardShortcutsUrlLinux?: string;
|
||||
readonly keyboardShortcutsUrlWin?: string;
|
||||
readonly introductoryVideosUrl?: string;
|
||||
readonly tipsAndTricksUrl?: string;
|
||||
readonly newsletterSignupUrl?: string;
|
||||
readonly twitterUrl?: string;
|
||||
readonly requestFeatureUrl?: string;
|
||||
readonly reportIssueUrl?: string;
|
||||
readonly reportMarketplaceIssueUrl?: string;
|
||||
readonly licenseUrl?: string;
|
||||
readonly privacyStatementUrl?: string;
|
||||
readonly telemetryOptOutUrl?: string;
|
||||
|
||||
readonly npsSurveyUrl?: string;
|
||||
readonly cesSurveyUrl?: string;
|
||||
readonly surveys?: readonly ISurveyData[];
|
||||
|
||||
readonly checksums?: { [path: string]: string; };
|
||||
readonly checksumFailMoreInfoUrl?: string;
|
||||
|
||||
readonly appCenter?: IAppCenterConfiguration;
|
||||
|
||||
readonly portable?: string;
|
||||
|
||||
readonly extensionKind?: { readonly [extensionId: string]: ('ui' | 'workspace' | 'web')[]; };
|
||||
readonly extensionSyncedKeys?: { readonly [extensionId: string]: string[]; };
|
||||
readonly extensionAllowedProposedApi?: readonly string[];
|
||||
readonly extensionUntrustedWorkspaceSupport?: { readonly [extensionId: string]: ExtensionUntrustedWorkspaceSupport };
|
||||
readonly extensionVirtualWorkspacesSupport?: { readonly [extensionId: string]: { default?: boolean, override?: boolean } };
|
||||
|
||||
readonly msftInternalDomains?: string[];
|
||||
readonly linkProtectionTrustedDomains?: readonly string[];
|
||||
|
||||
readonly 'configurationSync.store'?: ConfigurationSyncStore;
|
||||
|
||||
readonly darwinUniversalAssetId?: string;
|
||||
}
|
||||
|
||||
export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean };
|
||||
|
||||
export interface IAppCenterConfiguration {
|
||||
readonly 'win32-ia32': string;
|
||||
readonly 'win32-x64': string;
|
||||
readonly 'linux-x64': string;
|
||||
readonly 'darwin': string;
|
||||
}
|
||||
|
||||
export interface IConfigBasedExtensionTip {
|
||||
configPath: string;
|
||||
configName: string;
|
||||
recommendations: IStringDictionary<{ name: string, remotes?: string[], important?: boolean, isExtensionPack?: boolean }>;
|
||||
}
|
||||
|
||||
export interface IExeBasedExtensionTip {
|
||||
friendlyName: string;
|
||||
windowsPath?: string;
|
||||
important?: boolean;
|
||||
recommendations: IStringDictionary<{ name: string, important?: boolean, isExtensionPack?: boolean }>;
|
||||
}
|
||||
|
||||
export interface IRemoteExtensionTip {
|
||||
friendlyName: string;
|
||||
extensionId: string;
|
||||
}
|
||||
|
||||
export interface ISurveyData {
|
||||
surveyId: string;
|
||||
surveyUrl: string;
|
||||
languageId: string;
|
||||
editCount: number;
|
||||
userProbability: number;
|
||||
}
|
@ -9,6 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
* keyboardEvent.code
|
||||
*/
|
||||
export const enum ScanCode {
|
||||
DependsOnKbLayout = -1,
|
||||
None,
|
||||
|
||||
Hyper,
|
||||
@ -468,11 +469,11 @@ export class ScanCodeBinding {
|
||||
|
||||
(function () {
|
||||
for (let i = 0; i <= ScanCode.MAX_VALUE; i++) {
|
||||
IMMUTABLE_CODE_TO_KEY_CODE[i] = -1;
|
||||
IMMUTABLE_CODE_TO_KEY_CODE[i] = KeyCode.DependsOnKbLayout;
|
||||
}
|
||||
|
||||
for (let i = 0; i <= KeyCode.MAX_VALUE; i++) {
|
||||
IMMUTABLE_KEY_CODE_TO_CODE[i] = -1;
|
||||
IMMUTABLE_KEY_CODE_TO_CODE[i] = ScanCode.DependsOnKbLayout;
|
||||
}
|
||||
|
||||
function define(code: ScanCode, keyCode: KeyCode): void {
|
||||
|
@ -223,7 +223,7 @@ export class Scrollable extends Disposable {
|
||||
this._smoothScrolling = null;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this._smoothScrolling) {
|
||||
this._smoothScrolling.dispose();
|
||||
this._smoothScrolling = null;
|
||||
|
@ -18,6 +18,7 @@ namespace Severity {
|
||||
const _warning = 'warning';
|
||||
const _warn = 'warn';
|
||||
const _info = 'info';
|
||||
const _ignore = 'ignore';
|
||||
|
||||
/**
|
||||
* Parses 'error', 'warning', 'warn', 'info' in call casings
|
||||
@ -41,6 +42,15 @@ namespace Severity {
|
||||
}
|
||||
return Severity.Ignore;
|
||||
}
|
||||
|
||||
export function toString(severity: Severity): string {
|
||||
switch (severity) {
|
||||
case Severity.Error: return _error;
|
||||
case Severity.Warning: return _warning;
|
||||
case Severity.Info: return _info;
|
||||
default: return _ignore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Severity;
|
||||
|
@ -142,15 +142,21 @@ export interface ReadableBufferedStream<T> {
|
||||
}
|
||||
|
||||
export function isReadableStream<T>(obj: unknown): obj is ReadableStream<T> {
|
||||
const candidate = obj as ReadableStream<T>;
|
||||
const candidate = obj as ReadableStream<T> | undefined;
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return candidate && [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function');
|
||||
return [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function');
|
||||
}
|
||||
|
||||
export function isReadableBufferedStream<T>(obj: unknown): obj is ReadableBufferedStream<T> {
|
||||
const candidate = obj as ReadableBufferedStream<T>;
|
||||
const candidate = obj as ReadableBufferedStream<T> | undefined;
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return candidate && isReadableStream(candidate.stream) && Array.isArray(candidate.buffer) && typeof candidate.ended === 'boolean';
|
||||
return isReadableStream(candidate.stream) && Array.isArray(candidate.buffer) && typeof candidate.ended === 'boolean';
|
||||
}
|
||||
|
||||
export interface IReducer<T> {
|
||||
@ -625,6 +631,16 @@ export function toStream<T>(t: T, reducer: IReducer<T>): ReadableStream<T> {
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create an empty stream
|
||||
*/
|
||||
export function emptyStream(): ReadableStream<never> {
|
||||
const stream = newWriteableStream<never>(() => { throw new Error('not supported'); });
|
||||
stream.end();
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to convert a T into a Readable<T>.
|
||||
*/
|
||||
@ -658,3 +674,71 @@ export function transform<Original, Transformed>(stream: ReadableStreamEvents<Or
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to take an existing readable that will
|
||||
* have a prefix injected to the beginning.
|
||||
*/
|
||||
export function prefixedReadable<T>(prefix: T, readable: Readable<T>, reducer: IReducer<T>): Readable<T> {
|
||||
let prefixHandled = false;
|
||||
|
||||
return {
|
||||
read: () => {
|
||||
const chunk = readable.read();
|
||||
|
||||
// Handle prefix only once
|
||||
if (!prefixHandled) {
|
||||
prefixHandled = true;
|
||||
|
||||
// If we have also a read-result, make
|
||||
// sure to reduce it to a single result
|
||||
if (chunk !== null) {
|
||||
return reducer([prefix, chunk]);
|
||||
}
|
||||
|
||||
// Otherwise, just return prefix directly
|
||||
return prefix;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to take an existing stream that will
|
||||
* have a prefix injected to the beginning.
|
||||
*/
|
||||
export function prefixedStream<T>(prefix: T, stream: ReadableStream<T>, reducer: IReducer<T>): ReadableStream<T> {
|
||||
let prefixHandled = false;
|
||||
|
||||
const target = newWriteableStream<T>(reducer);
|
||||
|
||||
listenStream(stream, {
|
||||
onData: data => {
|
||||
|
||||
// Handle prefix only once
|
||||
if (!prefixHandled) {
|
||||
prefixHandled = true;
|
||||
|
||||
return target.write(reducer([prefix, data]));
|
||||
}
|
||||
|
||||
return target.write(data);
|
||||
},
|
||||
onError: error => target.error(error),
|
||||
onEnd: () => {
|
||||
|
||||
// Handle prefix only once
|
||||
if (!prefixHandled) {
|
||||
prefixHandled = true;
|
||||
|
||||
target.write(prefix);
|
||||
}
|
||||
|
||||
target.end();
|
||||
}
|
||||
});
|
||||
|
||||
return target;
|
||||
}
|
||||
|
@ -240,19 +240,19 @@ export function withUndefinedAsNull<T>(x: T | undefined): T | null {
|
||||
return typeof x === 'undefined' ? null : x;
|
||||
}
|
||||
|
||||
type AddFirstParameterToFunction<T, TargetFunctionsReturnType, FirstParameter> = T extends (...args: any[]) => TargetFunctionsReturnType ?
|
||||
// Function: add param to function
|
||||
(firstArg: FirstParameter, ...args: Parameters<T>) => ReturnType<T> :
|
||||
|
||||
// Else: just leave as is
|
||||
T;
|
||||
|
||||
/**
|
||||
* Allows to add a first parameter to functions of a type.
|
||||
*/
|
||||
export type AddFirstParameterToFunctions<Target, TargetFunctionsReturnType, FirstParameter> = {
|
||||
|
||||
// For every property
|
||||
[K in keyof Target]:
|
||||
|
||||
// Function: add param to function
|
||||
Target[K] extends (...args: any[]) => TargetFunctionsReturnType ? (firstArg: FirstParameter, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> :
|
||||
|
||||
// Else: just leave as is
|
||||
Target[K]
|
||||
// For every property
|
||||
[K in keyof Target]: AddFirstParameterToFunction<Target[K], TargetFunctionsReturnType, FirstParameter>;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -286,3 +286,7 @@ export function NotImplementedProxy<T>(name: string): { new(): T } {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function assertNever(value: never) {
|
||||
throw new Error('Unreachable');
|
||||
}
|
||||
|
@ -418,14 +418,14 @@ class Uri extends URI {
|
||||
_formatted: string | null = null;
|
||||
_fsPath: string | null = null;
|
||||
|
||||
get fsPath(): string {
|
||||
override get fsPath(): string {
|
||||
if (!this._fsPath) {
|
||||
this._fsPath = uriToFsPath(this, false);
|
||||
}
|
||||
return this._fsPath;
|
||||
}
|
||||
|
||||
toString(skipEncoding: boolean = false): string {
|
||||
override toString(skipEncoding: boolean = false): string {
|
||||
if (!skipEncoding) {
|
||||
if (!this._formatted) {
|
||||
this._formatted = _asFormatted(this, false);
|
||||
@ -437,7 +437,7 @@ class Uri extends URI {
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): UriComponents {
|
||||
override toJSON(): UriComponents {
|
||||
const res = <UriState>{
|
||||
$mid: 1
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ export class LineDecoder {
|
||||
private stringDecoder: sd.StringDecoder;
|
||||
private remaining: string | null;
|
||||
|
||||
constructor(encoding: string = 'utf8') {
|
||||
constructor(encoding: BufferEncoding = 'utf8') {
|
||||
this.stringDecoder = new sd.StringDecoder(encoding);
|
||||
this.remaining = null;
|
||||
}
|
||||
|
@ -56,8 +56,9 @@ export const virtualMachineHint: { value(): number } = new class {
|
||||
|
||||
const interfaces = networkInterfaces();
|
||||
for (let name in interfaces) {
|
||||
if (Object.prototype.hasOwnProperty.call(interfaces, name)) {
|
||||
for (const { mac, internal } of interfaces[name]) {
|
||||
const networkInterface = interfaces[name];
|
||||
if (networkInterface) {
|
||||
for (const { mac, internal } of networkInterface) {
|
||||
if (!internal) {
|
||||
interfaceCount += 1;
|
||||
if (this._isVirtualMachineMacAdress(mac.toUpperCase())) {
|
||||
|
@ -34,10 +34,13 @@ function doGetMac(): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const ifaces = networkInterfaces();
|
||||
for (const [, infos] of Object.entries(ifaces)) {
|
||||
for (const info of infos) {
|
||||
if (validateMacAddress(info.mac)) {
|
||||
return resolve(info.mac);
|
||||
for (let name in ifaces) {
|
||||
const networkInterface = ifaces[name];
|
||||
if (networkInterface) {
|
||||
for (const { mac } of networkInterface) {
|
||||
if (validateMacAddress(mac)) {
|
||||
return resolve(mac);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ export class LineProcess extends AbstractProcess<LineData> {
|
||||
this.stderrLineDecoder = stderrLineDecoder;
|
||||
}
|
||||
|
||||
protected handleClose(data: any, cc: ValueCallback<SuccessData>, pp: ProgressCallback<LineData>, ee: ErrorCallback): void {
|
||||
protected override handleClose(data: any, cc: ValueCallback<SuccessData>, pp: ProgressCallback<LineData>, ee: ErrorCallback): void {
|
||||
const stdoutLine = this.stdoutLineDecoder ? this.stdoutLineDecoder.end() : null;
|
||||
if (stdoutLine) {
|
||||
pp({ line: stdoutLine, source: Source.stdout });
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import { release, userInfo } from 'os';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { getFirstAvailablePowerShellInstallation } from 'vs/base/node/powershell';
|
||||
import * as processes from 'vs/base/node/processes';
|
||||
@ -11,10 +11,10 @@ import * as processes from 'vs/base/node/processes';
|
||||
/**
|
||||
* Gets the detected default shell for the _system_, not to be confused with VS Code's _default_
|
||||
* shell that the terminal uses by default.
|
||||
* @param p The platform to detect the shell of.
|
||||
* @param os The platform to detect the shell of.
|
||||
*/
|
||||
export async function getSystemShell(p: platform.Platform, env: platform.IProcessEnvironment): Promise<string> {
|
||||
if (p === platform.Platform.Windows) {
|
||||
export async function getSystemShell(os: platform.OperatingSystem, env: platform.IProcessEnvironment): Promise<string> {
|
||||
if (os === platform.OperatingSystem.Windows) {
|
||||
if (platform.isWindows) {
|
||||
return getSystemShellWindows();
|
||||
}
|
||||
@ -22,11 +22,11 @@ export async function getSystemShell(p: platform.Platform, env: platform.IProces
|
||||
return processes.getWindowsShell(env);
|
||||
}
|
||||
|
||||
return getSystemShellUnixLike(p, env);
|
||||
return getSystemShellUnixLike(os, env);
|
||||
}
|
||||
|
||||
export function getSystemShellSync(p: platform.Platform, env: platform.IProcessEnvironment): string {
|
||||
if (p === platform.Platform.Windows) {
|
||||
export function getSystemShellSync(os: platform.OperatingSystem, env: platform.IProcessEnvironment): string {
|
||||
if (os === platform.OperatingSystem.Windows) {
|
||||
if (platform.isWindows) {
|
||||
return getSystemShellWindowsSync(env);
|
||||
}
|
||||
@ -34,13 +34,13 @@ export function getSystemShellSync(p: platform.Platform, env: platform.IProcessE
|
||||
return processes.getWindowsShell(env);
|
||||
}
|
||||
|
||||
return getSystemShellUnixLike(p, env);
|
||||
return getSystemShellUnixLike(os, env);
|
||||
}
|
||||
|
||||
let _TERMINAL_DEFAULT_SHELL_UNIX_LIKE: string | null = null;
|
||||
function getSystemShellUnixLike(p: platform.Platform, env: platform.IProcessEnvironment): string {
|
||||
function getSystemShellUnixLike(os: platform.OperatingSystem, env: platform.IProcessEnvironment): string {
|
||||
// Only use $SHELL for the current OS
|
||||
if (platform.isLinux && p === platform.Platform.Mac || platform.isMacintosh && p === platform.Platform.Linux) {
|
||||
if (platform.isLinux && os === platform.OperatingSystem.Macintosh || platform.isMacintosh && os === platform.OperatingSystem.Linux) {
|
||||
return '/bin/bash';
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ function getSystemShellUnixLike(p: platform.Platform, env: platform.IProcessEnvi
|
||||
try {
|
||||
// It's possible for $SHELL to be unset, this API reads /etc/passwd. See https://github.com/github/codespaces/issues/1639
|
||||
// Node docs: "Throws a SystemError if a user has no username or homedir."
|
||||
unixLikeTerminal = os.userInfo().shell;
|
||||
unixLikeTerminal = userInfo().shell;
|
||||
} catch (err) { }
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ function getSystemShellWindowsSync(env: platform.IProcessEnvironment): string {
|
||||
return _TERMINAL_DEFAULT_SHELL_WINDOWS;
|
||||
}
|
||||
|
||||
const isAtLeastWindows10 = platform.isWindows && parseFloat(os.release()) >= 10;
|
||||
const isAtLeastWindows10 = platform.isWindows && parseFloat(release()) >= 10;
|
||||
const is32ProcessOn64Windows = env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||
const powerShellPath = `${env['windir']}\\${is32ProcessOn64Windows ? 'Sysnative' : 'System32'}\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
||||
return isAtLeastWindows10 ? powerShellPath : processes.getWindowsShell(env);
|
||||
|
@ -72,7 +72,7 @@ export class Client extends IPCClient implements IDisposable {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.protocol.disconnect();
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ class ProtocolReader extends Disposable {
|
||||
return this._incomingData.read(this._incomingData.byteLength);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this._isDisposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
@ -412,7 +412,7 @@ export class Client<TContext = string> extends IPCClient<TContext> {
|
||||
super(protocol, id, ipcLogger);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
const socket = this.protocol.getSocket();
|
||||
this.protocol.sendDisconnect();
|
||||
|
@ -32,7 +32,7 @@ export class Client extends IPCClient implements IDisposable {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.protocol.disconnect();
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
|
||||
this._register(this.socket.onClose(() => this._onClose.fire()));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this._zlibDeflateFlushWaitingCount > 0) {
|
||||
// Wait for any outstanding writes to finish before disposing
|
||||
this._register(this._onDidZlibFlush.event(() => {
|
||||
@ -581,7 +581,7 @@ export class Server extends IPCServer {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
|
@ -66,7 +66,7 @@ class TestIPCClient extends IPCClient<string> {
|
||||
super(protocol, id);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this._onDidDisconnect.fire();
|
||||
super.dispose();
|
||||
}
|
||||
@ -253,7 +253,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call success', async function () {
|
||||
const r = await ipcService.marco();
|
||||
return assert.equal(r, 'polo');
|
||||
return assert.strictEqual(r, 'polo');
|
||||
});
|
||||
|
||||
test('call error', async function () {
|
||||
@ -261,7 +261,7 @@ suite('Base IPC', function () {
|
||||
await ipcService.error('nice error');
|
||||
return assert.fail('should not reach here');
|
||||
} catch (err) {
|
||||
return assert.equal(err.message, 'nice error');
|
||||
return assert.strictEqual(err.message, 'nice error');
|
||||
}
|
||||
});
|
||||
|
||||
@ -304,20 +304,20 @@ suite('Base IPC', function () {
|
||||
ipcService.onPong(msg => messages.push(msg));
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, []);
|
||||
assert.deepStrictEqual(messages, []);
|
||||
service.ping('hello');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello']);
|
||||
assert.deepStrictEqual(messages, ['hello']);
|
||||
service.ping('world');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello', 'world']);
|
||||
assert.deepStrictEqual(messages, ['hello', 'world']);
|
||||
});
|
||||
|
||||
test('buffers in arrays', async function () {
|
||||
const r = await ipcService.buffersLength([VSBuffer.alloc(2), VSBuffer.alloc(3)]);
|
||||
return assert.equal(r, 5);
|
||||
return assert.strictEqual(r, 5);
|
||||
});
|
||||
});
|
||||
|
||||
@ -345,7 +345,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call success', async function () {
|
||||
const r = await ipcService.marco();
|
||||
return assert.equal(r, 'polo');
|
||||
return assert.strictEqual(r, 'polo');
|
||||
});
|
||||
|
||||
test('call error', async function () {
|
||||
@ -353,7 +353,7 @@ suite('Base IPC', function () {
|
||||
await ipcService.error('nice error');
|
||||
return assert.fail('should not reach here');
|
||||
} catch (err) {
|
||||
return assert.equal(err.message, 'nice error');
|
||||
return assert.strictEqual(err.message, 'nice error');
|
||||
}
|
||||
});
|
||||
|
||||
@ -363,15 +363,15 @@ suite('Base IPC', function () {
|
||||
ipcService.onPong(msg => messages.push(msg));
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, []);
|
||||
assert.deepStrictEqual(messages, []);
|
||||
service.ping('hello');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello']);
|
||||
assert.deepStrictEqual(messages, ['hello']);
|
||||
service.ping('world');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello', 'world']);
|
||||
assert.deepStrictEqual(messages, ['hello', 'world']);
|
||||
});
|
||||
|
||||
test('marshalling uri', async function () {
|
||||
@ -383,7 +383,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('buffers in arrays', async function () {
|
||||
const r = await ipcService.buffersLength([VSBuffer.alloc(2), VSBuffer.alloc(3)]);
|
||||
return assert.equal(r, 5);
|
||||
return assert.strictEqual(r, 5);
|
||||
});
|
||||
});
|
||||
|
||||
@ -411,7 +411,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call extra context', async function () {
|
||||
const r = await ipcService.context();
|
||||
return assert.equal(r, 'Super Context');
|
||||
return assert.strictEqual(r, 'Super Context');
|
||||
});
|
||||
});
|
||||
|
||||
@ -461,7 +461,7 @@ suite('Base IPC', function () {
|
||||
clientService1.ping('hello 1');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1']);
|
||||
assert.deepStrictEqual(pings, ['hello 1']);
|
||||
|
||||
const client2 = server.createConnection('client2');
|
||||
const clientService2 = new TestService();
|
||||
@ -472,19 +472,19 @@ suite('Base IPC', function () {
|
||||
clientService2.ping('hello 2');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2']);
|
||||
|
||||
client1.dispose();
|
||||
clientService1.ping('hello 1');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2']);
|
||||
|
||||
await timeout(1);
|
||||
clientService2.ping('hello again 2');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
|
||||
|
||||
client2.dispose();
|
||||
server.dispose();
|
||||
|
@ -22,8 +22,8 @@ suite('IPC, Child Process', () => {
|
||||
const service = new TestServiceClient(channel);
|
||||
|
||||
const result = service.pong('ping').then(r => {
|
||||
assert.equal(r.incoming, 'ping');
|
||||
assert.equal(r.outgoing, 'pong');
|
||||
assert.strictEqual(r.incoming, 'ping');
|
||||
assert.strictEqual(r.outgoing, 'pong');
|
||||
});
|
||||
|
||||
return result.finally(() => client.dispose());
|
||||
@ -37,7 +37,7 @@ suite('IPC, Child Process', () => {
|
||||
const event = new Promise((c, e) => {
|
||||
service.onMarco(({ answer }) => {
|
||||
try {
|
||||
assert.equal(answer, 'polo');
|
||||
assert.strictEqual(answer, 'polo');
|
||||
c(undefined);
|
||||
} catch (err) {
|
||||
e(err);
|
||||
@ -60,17 +60,17 @@ suite('IPC, Child Process', () => {
|
||||
const disposable = service.onMarco(() => count++);
|
||||
|
||||
const result = service.marco().then(async answer => {
|
||||
assert.equal(answer, 'polo');
|
||||
assert.equal(count, 1);
|
||||
assert.strictEqual(answer, 'polo');
|
||||
assert.strictEqual(count, 1);
|
||||
|
||||
const answer_1 = await service.marco();
|
||||
assert.equal(answer_1, 'polo');
|
||||
assert.equal(count, 2);
|
||||
assert.strictEqual(answer_1, 'polo');
|
||||
assert.strictEqual(count, 2);
|
||||
disposable.dispose();
|
||||
|
||||
const answer_2 = await service.marco();
|
||||
assert.equal(answer_2, 'polo');
|
||||
assert.equal(count, 2);
|
||||
assert.strictEqual(answer_2, 'polo');
|
||||
assert.strictEqual(count, 2);
|
||||
});
|
||||
|
||||
return result.finally(() => client.dispose());
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
.quick-input-titlebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quick-input-left-action-bar {
|
||||
@ -22,10 +23,6 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.quick-input-left-action-bar.monaco-action-bar .actions-container {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.quick-input-title {
|
||||
padding: 3px 0px;
|
||||
text-align: center;
|
||||
@ -37,12 +34,14 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.quick-input-right-action-bar > .actions-container {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.quick-input-titlebar .monaco-action-bar .action-label.codicon {
|
||||
margin: 0;
|
||||
width: 19px;
|
||||
height: 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.quick-input-description {
|
||||
@ -260,10 +259,8 @@
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
padding: 0 2px;
|
||||
vertical-align: middle;
|
||||
margin-right: 4px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar {
|
||||
@ -274,10 +271,6 @@
|
||||
margin-right: 4px; /* separate from scrollbar */
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
|
||||
margin-right: 4px; /* separate actions */
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,
|
||||
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label,
|
||||
.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label {
|
||||
|
@ -32,6 +32,7 @@ import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
|
||||
export interface IQuickInputOptions {
|
||||
idPrefix: string;
|
||||
@ -57,6 +58,7 @@ export interface IQuickInputStyles {
|
||||
countBadge: ICountBadgetyles;
|
||||
button: IButtonStyles;
|
||||
progressBar: IProgressBarStyles;
|
||||
keybindingLabel: IKeybindingLabelStyles;
|
||||
list: IListStyles & { pickerGroupBorder?: Color; pickerGroupForeground?: Color; };
|
||||
}
|
||||
|
||||
@ -410,7 +412,7 @@ class QuickInput extends Disposable implements IQuickInput {
|
||||
|
||||
readonly onDispose = this.onDisposeEmitter.event;
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.hide();
|
||||
this.onDisposeEmitter.fire();
|
||||
|
||||
@ -694,7 +696,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
override show() {
|
||||
if (!this.visible) {
|
||||
this.visibleDisposables.add(
|
||||
this.ui.inputBox.onDidChange(value => {
|
||||
@ -884,20 +886,11 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
});
|
||||
}
|
||||
|
||||
protected update() {
|
||||
protected override update() {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
let hideInput = false;
|
||||
let inputShownJustForScreenReader = false;
|
||||
if (!!this._hideInput && this._items.length > 0) {
|
||||
if (this.ui.isScreenReaderOptimized()) {
|
||||
// Always show input if screen reader attached https://github.com/microsoft/vscode/issues/94360
|
||||
inputShownJustForScreenReader = true;
|
||||
} else {
|
||||
hideInput = true;
|
||||
}
|
||||
}
|
||||
const hideInput = !!this._hideInput && this._items.length > 0;
|
||||
this.ui.container.classList.toggle('hidden-input', hideInput && !this.description);
|
||||
const visibilities: Visibilities = {
|
||||
title: !!this.title || !!this.step || !!this.buttons.length,
|
||||
@ -925,13 +918,9 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
if (this.ui.inputBox.placeholder !== (this.placeholder || '')) {
|
||||
this.ui.inputBox.placeholder = (this.placeholder || '');
|
||||
}
|
||||
if (inputShownJustForScreenReader) {
|
||||
this.ui.inputBox.ariaLabel = '';
|
||||
} else {
|
||||
const ariaLabel = this.ariaLabel || this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;
|
||||
if (this.ui.inputBox.ariaLabel !== ariaLabel) {
|
||||
this.ui.inputBox.ariaLabel = ariaLabel;
|
||||
}
|
||||
const ariaLabel = this.ariaLabel || this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;
|
||||
if (this.ui.inputBox.ariaLabel !== ariaLabel) {
|
||||
this.ui.inputBox.ariaLabel = ariaLabel;
|
||||
}
|
||||
this.ui.list.matchOnDescription = this.matchOnDescription;
|
||||
this.ui.list.matchOnDetail = this.matchOnDetail;
|
||||
@ -1063,7 +1052,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
|
||||
readonly onDidAccept = this.onDidAcceptEmitter.event;
|
||||
|
||||
show() {
|
||||
override show() {
|
||||
if (!this.visible) {
|
||||
this.visibleDisposables.add(
|
||||
this.ui.inputBox.onDidChange(value => {
|
||||
@ -1079,7 +1068,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
super.show();
|
||||
}
|
||||
|
||||
protected update() {
|
||||
protected override update() {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
@ -1388,8 +1377,12 @@ export class QuickInputController extends Disposable {
|
||||
const index = input.items.indexOf(event.item);
|
||||
if (index !== -1) {
|
||||
const items = input.items.slice();
|
||||
items.splice(index, 1);
|
||||
const removed = items.splice(index, 1);
|
||||
const activeItems = input.activeItems.filter((ai) => ai !== removed[0]);
|
||||
input.items = items;
|
||||
if (activeItems) {
|
||||
input.activeItems = activeItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
})),
|
||||
@ -1729,6 +1722,34 @@ export class QuickInputController extends Disposable {
|
||||
if (this.styles.list.pickerGroupForeground) {
|
||||
content.push(`.quick-input-list .quick-input-list-separator { color: ${this.styles.list.pickerGroupForeground}; }`);
|
||||
}
|
||||
|
||||
if (
|
||||
this.styles.keybindingLabel.keybindingLabelBackground ||
|
||||
this.styles.keybindingLabel.keybindingLabelBorder ||
|
||||
this.styles.keybindingLabel.keybindingLabelBottomBorder ||
|
||||
this.styles.keybindingLabel.keybindingLabelShadow ||
|
||||
this.styles.keybindingLabel.keybindingLabelForeground
|
||||
) {
|
||||
content.push('.quick-input-list .monaco-keybinding > .monaco-keybinding-key {');
|
||||
if (this.styles.keybindingLabel.keybindingLabelBackground) {
|
||||
content.push(`background-color: ${this.styles.keybindingLabel.keybindingLabelBackground};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelBorder) {
|
||||
// Order matters here. `border-color` must come before `border-bottom-color`.
|
||||
content.push(`border-color: ${this.styles.keybindingLabel.keybindingLabelBorder};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelBottomBorder) {
|
||||
content.push(`border-bottom-color: ${this.styles.keybindingLabel.keybindingLabelBottomBorder};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelShadow) {
|
||||
content.push(`box-shadow: inset 0 -1px 0 ${this.styles.keybindingLabel.keybindingLabelShadow};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelForeground) {
|
||||
content.push(`color: ${this.styles.keybindingLabel.keybindingLabelForeground};`);
|
||||
}
|
||||
content.push('}');
|
||||
}
|
||||
|
||||
const newStyles = content.join('\n');
|
||||
if (newStyles !== this.ui.styleSheet.textContent) {
|
||||
this.ui.styleSheet.textContent = newStyles;
|
||||
|
@ -27,6 +27,7 @@ import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput'
|
||||
import { IListOptions, List, IListStyles, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { getCodiconAriaLabel } from 'vs/base/common/codicons';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@ -427,7 +428,7 @@ export class QuickInputList {
|
||||
const saneDescription = item.description && item.description.replace(/\r?\n/g, ' ');
|
||||
const saneDetail = item.detail && item.detail.replace(/\r?\n/g, ' ');
|
||||
const saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail]
|
||||
.map(s => s && parseLabelWithIcons(s).text)
|
||||
.map(s => getCodiconAriaLabel(s))
|
||||
.filter(s => !!s)
|
||||
.join(', ');
|
||||
|
||||
@ -603,6 +604,7 @@ export class QuickInputList {
|
||||
|
||||
// Filter by value (since we support icons in labels, use $(..) aware fuzzy matching)
|
||||
else {
|
||||
let currentSeparator: IQuickPickSeparator | undefined;
|
||||
this.elements.forEach(element => {
|
||||
const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : undefined;
|
||||
const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDescription || ''))) : undefined;
|
||||
@ -621,6 +623,16 @@ export class QuickInputList {
|
||||
element.hidden = !element.item.alwaysShow;
|
||||
}
|
||||
element.separator = undefined;
|
||||
|
||||
// we can show the separator unless the list gets sorted by match
|
||||
if (!this.sortByLabel) {
|
||||
const previous = element.index && this.inputElements[element.index - 1];
|
||||
currentSeparator = previous && previous.type === 'separator' ? previous : currentSeparator;
|
||||
if (currentSeparator && !element.hidden) {
|
||||
element.separator = currentSeparator;
|
||||
currentSeparator = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,7 @@ export interface IQuickPickItemButtonContext<T extends IQuickPickItem> extends I
|
||||
export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
|
||||
|
||||
|
||||
//region Fuzzy Scorer Support
|
||||
//#region Fuzzy Scorer Support
|
||||
|
||||
export type IQuickPickItemWithResource = IQuickPickItem & { resource?: URI };
|
||||
|
||||
|
52
lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts
Normal file
52
lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IProductConfiguration } from 'vs/base/common/product';
|
||||
|
||||
|
||||
// #######################################################################
|
||||
// ### ###
|
||||
// ### Types we need in a common layer for reuse ###
|
||||
// ### ###
|
||||
// #######################################################################
|
||||
|
||||
|
||||
/**
|
||||
* The common properties required for any sandboxed
|
||||
* renderer to function.
|
||||
*/
|
||||
export interface ISandboxConfiguration {
|
||||
|
||||
/**
|
||||
* Identifier of the sandboxed renderer.
|
||||
*/
|
||||
windowId: number;
|
||||
|
||||
/**
|
||||
* Absolute installation path.
|
||||
*/
|
||||
appRoot: string;
|
||||
|
||||
/**
|
||||
* Per window process environment.
|
||||
*/
|
||||
userEnv: IProcessEnvironment;
|
||||
|
||||
/**
|
||||
* Product configuration.
|
||||
*/
|
||||
product: IProductConfiguration;
|
||||
|
||||
/**
|
||||
* Configured zoom level.
|
||||
*/
|
||||
zoomLevel?: number;
|
||||
|
||||
/**
|
||||
* @deprecated to be removed soon
|
||||
*/
|
||||
nodeCachedDataDir?: string;
|
||||
}
|
@ -9,6 +9,122 @@
|
||||
|
||||
const { ipcRenderer, webFrame, crashReporter, contextBridge } = require('electron');
|
||||
|
||||
//#region Utilities
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @returns {true | never}
|
||||
*/
|
||||
function validateIPC(channel) {
|
||||
if (!channel || !channel.startsWith('vscode:')) {
|
||||
throw new Error(`Unsupported event IPC channel '${channel}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @returns {type is 'uncaughtException'}
|
||||
*/
|
||||
function validateProcessEventType(type) {
|
||||
if (type !== 'uncaughtException') {
|
||||
throw new Error(`Unsupported process event '${type}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key the name of the process argument to parse
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
function parseArgv(key) {
|
||||
for (const arg of process.argv) {
|
||||
if (arg.indexOf(`--${key}=`) === 0) {
|
||||
return arg.split('=')[1];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Resolve Configuration
|
||||
|
||||
/**
|
||||
* @typedef {import('../common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
*/
|
||||
|
||||
/** @type {ISandboxConfiguration | undefined} */
|
||||
let configuration = undefined;
|
||||
|
||||
/** @type {Promise<ISandboxConfiguration>} */
|
||||
const resolveConfiguration = (async () => {
|
||||
const windowConfigIpcChannel = parseArgv('vscode-window-config');
|
||||
if (!windowConfigIpcChannel) {
|
||||
throw new Error('Preload: did not find expected vscode-window-config in renderer process arguments list.');
|
||||
}
|
||||
|
||||
try {
|
||||
if (validateIPC(windowConfigIpcChannel)) {
|
||||
|
||||
// Resolve configuration from electron-main
|
||||
configuration = await ipcRenderer.invoke(windowConfigIpcChannel);
|
||||
|
||||
// Apply `userEnv` directly
|
||||
Object.assign(process.env, configuration.userEnv);
|
||||
|
||||
// Apply zoom level early before even building the
|
||||
// window DOM elements to avoid UI flicker. We always
|
||||
// have to set the zoom level from within the window
|
||||
// because Chrome has it's own way of remembering zoom
|
||||
// settings per origin (if vscode-file:// is used) and
|
||||
// we want to ensure that the user configuration wins.
|
||||
webFrame.setZoomLevel(configuration.zoomLevel ?? 0);
|
||||
|
||||
return configuration;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Preload: unable to fetch vscode-window-config: ${error}`);
|
||||
}
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Resolve Shell Environment
|
||||
|
||||
/**
|
||||
* If VSCode is not run from a terminal, we should resolve additional
|
||||
* shell specific environment from the OS shell to ensure we are seeing
|
||||
* all development related environment variables. We do this from the
|
||||
* main process because it may involve spawning a shell.
|
||||
*
|
||||
* @type {Promise<typeof process.env>}
|
||||
*/
|
||||
const resolveShellEnv = (async () => {
|
||||
|
||||
// Resolve `userEnv` from configuration and
|
||||
// `shellEnv` from the main side
|
||||
const [userEnv, shellEnv] = await Promise.all([
|
||||
(async () => (await resolveConfiguration).userEnv)(),
|
||||
ipcRenderer.invoke('vscode:fetchShellEnv')
|
||||
]);
|
||||
|
||||
if (!process.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) {
|
||||
// Assign all keys of the shell environment to our process environment
|
||||
// But make sure that the user environment wins in the end over shell environment
|
||||
Object.assign(process.env, shellEnv, userEnv);
|
||||
}
|
||||
|
||||
return { ...process.env, ...shellEnv, ...userEnv };
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Globals Definition
|
||||
|
||||
// #######################################################################
|
||||
// ### ###
|
||||
// ### !!! DO NOT USE GET/SET PROPERTIES ANYWHERE HERE !!! ###
|
||||
@ -17,14 +133,21 @@
|
||||
// ### ###
|
||||
// #######################################################################
|
||||
|
||||
/**
|
||||
* @type {import('../electron-sandbox/globals')}
|
||||
*/
|
||||
const globals = {
|
||||
|
||||
/**
|
||||
* A minimal set of methods exposed from Electron's `ipcRenderer`
|
||||
* to support communication to main process.
|
||||
*
|
||||
* @type {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @typedef {import('../electron-sandbox/electronTypes').IpcRenderer} IpcRenderer
|
||||
* @typedef {import('electron').IpcRendererEvent} IpcRendererEvent
|
||||
*
|
||||
* @type {IpcRenderer}
|
||||
*/
|
||||
|
||||
ipcRenderer: {
|
||||
|
||||
/**
|
||||
@ -50,8 +173,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
on(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@ -63,8 +186,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
once(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@ -76,8 +199,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
removeListener(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@ -100,7 +223,7 @@
|
||||
*/
|
||||
connect(channelRequest, channelResponse, requestNonce) {
|
||||
if (validateIPC(channelRequest) && validateIPC(channelResponse)) {
|
||||
const responseListener = (/** @type {import('electron').IpcRendererEvent} */ e, /** @type {string} */ responseNonce) => {
|
||||
const responseListener = (/** @type {IpcRendererEvent} */ e, /** @type {string} */ responseNonce) => {
|
||||
// validate that the nonce from the response is the same
|
||||
// as when requested. and if so, use `postMessage` to
|
||||
// send the `MessagePort` safely over, even when context
|
||||
@ -157,7 +280,9 @@
|
||||
* Note: when `sandbox` is enabled, the only properties available
|
||||
* are https://github.com/electron/electron/blob/master/docs/api/process.md#sandbox
|
||||
*
|
||||
* @type {import('../electron-sandbox/globals').ISandboxNodeProcess}
|
||||
* @typedef {import('../electron-sandbox/globals').ISandboxNodeProcess} ISandboxNodeProcess
|
||||
*
|
||||
* @type {ISandboxNodeProcess}
|
||||
*/
|
||||
process: {
|
||||
get platform() { return process.platform; },
|
||||
@ -178,16 +303,8 @@
|
||||
/**
|
||||
* @returns {Promise<typeof process.env>}
|
||||
*/
|
||||
getShellEnv() {
|
||||
return shellEnv;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {{[key: string]: string}} userEnv
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
resolveEnv(userEnv) {
|
||||
return resolveEnv(userEnv);
|
||||
shellEnv() {
|
||||
return resolveShellEnv;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -200,7 +317,7 @@
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {Function} callback
|
||||
* @returns {import('../electron-sandbox/globals').ISandboxNodeProcess}
|
||||
* @returns {ISandboxNodeProcess}
|
||||
*/
|
||||
on(type, callback) {
|
||||
if (validateProcessEventType(type)) {
|
||||
@ -210,6 +327,37 @@
|
||||
return this;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Some information about the context we are running in.
|
||||
*
|
||||
* @type {import('../electron-sandbox/globals').ISandboxContext}
|
||||
*/
|
||||
context: {
|
||||
|
||||
/**
|
||||
* A configuration object made accessible from the main side
|
||||
* to configure the sandbox browser window.
|
||||
*
|
||||
* Note: intentionally not using a getter here because the
|
||||
* actual value will be set after `resolveConfiguration`
|
||||
* has finished.
|
||||
*
|
||||
* @returns {ISandboxConfiguration | undefined}
|
||||
*/
|
||||
configuration() {
|
||||
return configuration;
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows to await the resolution of the configuration object.
|
||||
*
|
||||
* @returns {Promise<ISandboxConfiguration>}
|
||||
*/
|
||||
async resolveConfiguration() {
|
||||
return resolveConfiguration;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -231,69 +379,4 @@
|
||||
// @ts-ignore
|
||||
window.vscode = globals;
|
||||
}
|
||||
|
||||
//#region Utilities
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @returns {true | never}
|
||||
*/
|
||||
function validateIPC(channel) {
|
||||
if (!channel || !channel.startsWith('vscode:')) {
|
||||
throw new Error(`Unsupported event IPC channel '${channel}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @returns {type is 'uncaughtException'}
|
||||
*/
|
||||
function validateProcessEventType(type) {
|
||||
if (type !== 'uncaughtException') {
|
||||
throw new Error(`Unsupported process event '${type}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @type {Promise<typeof process.env> | undefined} */
|
||||
let shellEnv = undefined;
|
||||
|
||||
/**
|
||||
* If VSCode is not run from a terminal, we should resolve additional
|
||||
* shell specific environment from the OS shell to ensure we are seeing
|
||||
* all development related environment variables. We do this from the
|
||||
* main process because it may involve spawning a shell.
|
||||
*
|
||||
* @param {{[key: string]: string}} userEnv
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function resolveEnv(userEnv) {
|
||||
if (!shellEnv) {
|
||||
|
||||
// Apply `userEnv` directly
|
||||
Object.assign(process.env, userEnv);
|
||||
|
||||
// Resolve `shellEnv` from the main side
|
||||
shellEnv = new Promise(function (resolve) {
|
||||
ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnvResult) {
|
||||
if (!process.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) {
|
||||
// Assign all keys of the shell environment to our process environment
|
||||
// But make sure that the user environment wins in the end over shell environment
|
||||
Object.assign(process.env, shellEnvResult, userEnv);
|
||||
}
|
||||
|
||||
resolve({ ...process.env, ...shellEnvResult, ...userEnv });
|
||||
});
|
||||
|
||||
ipcRenderer.send('vscode:fetchShellEnv');
|
||||
});
|
||||
}
|
||||
|
||||
await shellEnv;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}());
|
||||
|
@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { globals, INodeProcess, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ISandboxConfiguration } from 'vs/base/parts/sandbox/common/sandboxTypes';
|
||||
import { ProcessMemoryInfo, CrashReporter, IpcRenderer, WebFrame } from 'vs/base/parts/sandbox/electron-sandbox/electronTypes';
|
||||
|
||||
/**
|
||||
@ -74,8 +75,8 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
getProcessMemoryInfo: () => Promise<ProcessMemoryInfo>;
|
||||
|
||||
/**
|
||||
* A custom method we add to `process`: Resolve the true process environment to use and
|
||||
* apply it to `process.env`.
|
||||
* Returns a process environment that includes all shell environment variables even if
|
||||
* the application was not started from a shell / terminal / console.
|
||||
*
|
||||
* There are different layers of environment that will apply:
|
||||
* - `process.env`: this is the actual environment of the process before this method
|
||||
@ -86,17 +87,8 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
* from a terminal and changed certain variables
|
||||
*
|
||||
* The order of overwrites is `process.env` < `shellEnv` < `userEnv`.
|
||||
*
|
||||
* It is critical that every process awaits this method early on startup to get the right
|
||||
* set of environment in `process.env`.
|
||||
*/
|
||||
resolveEnv(userEnv: IProcessEnvironment): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns a process environment that includes any shell environment even if the application
|
||||
* was not started from a shell / terminal / console.
|
||||
*/
|
||||
getShellEnv(): Promise<IProcessEnvironment>;
|
||||
shellEnv(): Promise<IProcessEnvironment>;
|
||||
}
|
||||
|
||||
export interface IpcMessagePort {
|
||||
@ -114,8 +106,24 @@ export interface IpcMessagePort {
|
||||
connect(channelRequest: string, channelResponse: string, requestNonce: string): void;
|
||||
}
|
||||
|
||||
export interface ISandboxContext {
|
||||
|
||||
/**
|
||||
* A configuration object made accessible from the main side
|
||||
* to configure the sandbox browser window. Will be `undefined`
|
||||
* for as long as `resolveConfiguration` is not awaited.
|
||||
*/
|
||||
configuration(): ISandboxConfiguration | undefined;
|
||||
|
||||
/**
|
||||
* Allows to await the resolution of the configuration object.
|
||||
*/
|
||||
resolveConfiguration(): Promise<ISandboxConfiguration>;
|
||||
}
|
||||
|
||||
export const ipcRenderer: IpcRenderer = globals.vscode.ipcRenderer;
|
||||
export const ipcMessagePort: IpcMessagePort = globals.vscode.ipcMessagePort;
|
||||
export const webFrame: WebFrame = globals.vscode.webFrame;
|
||||
export const crashReporter: CrashReporter = globals.vscode.crashReporter;
|
||||
export const process: ISandboxNodeProcess = globals.vscode.process;
|
||||
export const context: ISandboxContext = globals.vscode.context;
|
||||
|
@ -4,13 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ipcRenderer, crashReporter, webFrame, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ipcRenderer, crashReporter, webFrame, context, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
|
||||
suite('Sandbox', () => {
|
||||
test('globals', () => {
|
||||
test('globals', async () => {
|
||||
assert.ok(typeof ipcRenderer.send === 'function');
|
||||
assert.ok(typeof crashReporter.addExtraParameter === 'function');
|
||||
assert.ok(typeof webFrame.setZoomLevel === 'function');
|
||||
assert.ok(typeof process.platform === 'string');
|
||||
|
||||
const config = await context.resolveConfiguration();
|
||||
assert.ok(config);
|
||||
assert.ok(context.configuration());
|
||||
});
|
||||
});
|
||||
|
@ -320,7 +320,7 @@ export class Storage extends Disposable implements IStorage {
|
||||
return new Promise(resolve => this.whenFlushedCallbacks.push(resolve));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.flushDelayer.cancel(); // workaround https://github.com/microsoft/vscode/issues/116777
|
||||
this.flushDelayer.dispose();
|
||||
|
||||
|
@ -111,7 +111,7 @@ flakySuite('Storage Library', function () {
|
||||
|
||||
class TestSQLiteStorageDatabase extends SQLiteStorageDatabase {
|
||||
private readonly _onDidChangeItemsExternal = new Emitter<IStorageItemsChangeEvent>();
|
||||
get onDidChangeItemsExternal(): Event<IStorageItemsChangeEvent> { return this._onDidChangeItemsExternal.event; }
|
||||
override get onDidChangeItemsExternal(): Event<IStorageItemsChangeEvent> { return this._onDidChangeItemsExternal.event; }
|
||||
|
||||
fireDidChangeItemsExternal(event: IStorageItemsChangeEvent): void {
|
||||
this._onDidChangeItemsExternal.fire(event);
|
||||
|
@ -59,8 +59,8 @@ suite('Comparers', () => {
|
||||
// name-only comparisons
|
||||
assert(compareFileNames('a', 'A') !== compareLocale('a', 'A'), 'the same letter does not sort by locale');
|
||||
assert(compareFileNames('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter does not sort by locale');
|
||||
assert.notDeepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNames), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order');
|
||||
assert.notDeepEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNames), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents do not sort in locale order');
|
||||
assert.notDeepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNames), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order');
|
||||
assert.notDeepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNames), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents do not sort in locale order');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNames('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order');
|
||||
|
@ -44,8 +44,14 @@ suite('FormattedTextRenderer', () => {
|
||||
result = renderFormattedText('__italics__');
|
||||
assert.strictEqual(result.innerHTML, '<i>italics</i>');
|
||||
|
||||
result = renderFormattedText('this string has **bold** and __italics__');
|
||||
assert.strictEqual(result.innerHTML, 'this string has <b>bold</b> and <i>italics</i>');
|
||||
result = renderFormattedText('``code``');
|
||||
assert.strictEqual(result.innerHTML, '``code``');
|
||||
|
||||
result = renderFormattedText('``code``', { renderCodeSegements: true });
|
||||
assert.strictEqual(result.innerHTML, '<code>code</code>');
|
||||
|
||||
result = renderFormattedText('this string has **bold**, __italics__, and ``code``!!', { renderCodeSegements: true });
|
||||
assert.strictEqual(result.innerHTML, 'this string has <b>bold</b>, <i>italics</i>, and <code>code</code>!!');
|
||||
});
|
||||
|
||||
test('no formatting', () => {
|
||||
@ -96,6 +102,26 @@ suite('FormattedTextRenderer', () => {
|
||||
assert.strictEqual(callbackCalled, true);
|
||||
});
|
||||
|
||||
test('fancier action', () => {
|
||||
let callbackCalled = false;
|
||||
let result: HTMLElement = renderFormattedText('``__**[[action]]**__``', {
|
||||
renderCodeSegements: true,
|
||||
actionHandler: {
|
||||
callback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
},
|
||||
disposeables: store
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.innerHTML, '<code><i><b><a href="#">action</a></b></i></code>');
|
||||
|
||||
let event: MouseEvent = <any>document.createEvent('MouseEvent');
|
||||
event.initEvent('click', true, true);
|
||||
result.firstChild!.firstChild!.firstChild!.firstChild!.dispatchEvent(event);
|
||||
assert.strictEqual(callbackCalled, true);
|
||||
});
|
||||
|
||||
test('escaped formatting', () => {
|
||||
let result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*');
|
||||
assert.strictEqual(result.children.length, 0);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user