mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 10:38:31 -05:00
Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d
This commit is contained in:
committed by
AzureDataStudio
parent
a8a7559229
commit
1388493cc1
24
src/bootstrap-fork.js
vendored
24
src/bootstrap-fork.js
vendored
@@ -7,15 +7,16 @@
|
||||
'use strict';
|
||||
|
||||
const bootstrap = require('./bootstrap');
|
||||
const bootstrapNode = require('./bootstrap-node');
|
||||
|
||||
// Remove global paths from the node module lookup
|
||||
bootstrap.removeGlobalNodeModuleLookupPaths();
|
||||
bootstrapNode.removeGlobalNodeModuleLookupPaths();
|
||||
|
||||
// Enable ASAR in our forked processes
|
||||
bootstrap.enableASARSupport();
|
||||
|
||||
if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) {
|
||||
bootstrap.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']);
|
||||
bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']);
|
||||
}
|
||||
|
||||
// Configure: pipe logging to parent process
|
||||
@@ -39,6 +40,7 @@ configureCrashReporter();
|
||||
// Load AMD entry point
|
||||
require('./bootstrap-amd').load(process.env['AMD_ENTRYPOINT']);
|
||||
|
||||
|
||||
//#region Helpers
|
||||
|
||||
function pipeLoggingToParent() {
|
||||
@@ -49,8 +51,6 @@ function pipeLoggingToParent() {
|
||||
const seen = [];
|
||||
const argsArray = [];
|
||||
|
||||
let res;
|
||||
|
||||
// Massage some arguments with special treatment
|
||||
if (args.length) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
@@ -85,7 +85,7 @@ function pipeLoggingToParent() {
|
||||
}
|
||||
|
||||
try {
|
||||
res = JSON.stringify(argsArray, function (key, value) {
|
||||
const res = JSON.stringify(argsArray, function (key, value) {
|
||||
|
||||
// Objects get special treatment to prevent circles
|
||||
if (isObject(value) || Array.isArray(value)) {
|
||||
@@ -98,15 +98,15 @@ function pipeLoggingToParent() {
|
||||
|
||||
return value;
|
||||
});
|
||||
|
||||
if (res.length > MAX_LENGTH) {
|
||||
return 'Output omitted for a large object that exceeds the limits';
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (error) {
|
||||
return 'Output omitted for an object that cannot be inspected (' + error.toString() + ')';
|
||||
return `Output omitted for an object that cannot be inspected ('${error.toString()}')`;
|
||||
}
|
||||
|
||||
if (res && res.length > MAX_LENGTH) {
|
||||
return 'Output omitted for a large object that exceeds the limits';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
60
src/bootstrap-node.js
vendored
Normal file
60
src/bootstrap-node.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Add support for redirecting the loading of node modules
|
||||
*
|
||||
* @param {string} injectPath
|
||||
*/
|
||||
exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
if (!injectPath) {
|
||||
throw new Error('Missing injectPath');
|
||||
}
|
||||
|
||||
const Module = require('module');
|
||||
const path = require('path');
|
||||
|
||||
const nodeModulesPath = path.join(__dirname, '../node_modules');
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent) {
|
||||
const paths = originalResolveLookupPaths(moduleName, parent);
|
||||
if (Array.isArray(paths)) {
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === nodeModulesPath) {
|
||||
paths.splice(i, 0, injectPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
};
|
||||
|
||||
exports.removeGlobalNodeModuleLookupPaths = function () {
|
||||
const Module = require('module');
|
||||
// @ts-ignore
|
||||
const globalPaths = Module.globalPaths;
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent) {
|
||||
const paths = originalResolveLookupPaths(moduleName, parent);
|
||||
let commonSuffixLength = 0;
|
||||
while (commonSuffixLength < paths.length && paths[paths.length - 1 - commonSuffixLength] === globalPaths[globalPaths.length - 1 - commonSuffixLength]) {
|
||||
commonSuffixLength++;
|
||||
}
|
||||
return paths.slice(0, paths.length - commonSuffixLength);
|
||||
};
|
||||
};
|
||||
409
src/bootstrap-window.js
vendored
409
src/bootstrap-window.js
vendored
@@ -3,235 +3,232 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path="typings/require.d.ts" />
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const bootstrap = require('./bootstrap');
|
||||
// Simple module style to support node.js and browser environments
|
||||
(function (globalThis, factory) {
|
||||
|
||||
/**
|
||||
* @param {object} destination
|
||||
* @param {object} source
|
||||
* @returns {object}
|
||||
*/
|
||||
exports.assign = function assign(destination, source) {
|
||||
return Object.keys(source).reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
|
||||
};
|
||||
// Node.js
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} modulePaths
|
||||
* @param {(result, configuration: object) => any} resultCallback
|
||||
* @param {{ forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options
|
||||
*/
|
||||
exports.load = function (modulePaths, resultCallback, options) {
|
||||
// Browser
|
||||
else {
|
||||
globalThis.MonacoBootstrapWindow = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
const path = require.__$__nodeRequire('path');
|
||||
const webFrame = require.__$__nodeRequire('electron').webFrame;
|
||||
const ipc = require.__$__nodeRequire('electron').ipcRenderer;
|
||||
const bootstrap = globalThis.MonacoBootstrap;
|
||||
|
||||
const webFrame = require('electron').webFrame;
|
||||
const path = require('path');
|
||||
|
||||
const args = parseURLQueryArgs();
|
||||
/**
|
||||
* // configuration: INativeWindowConfiguration
|
||||
* @type {{
|
||||
* zoomLevel?: number,
|
||||
* extensionDevelopmentPath?: string[],
|
||||
* extensionTestsPath?: string,
|
||||
* userEnv?: { [key: string]: string | undefined },
|
||||
* appRoot?: string,
|
||||
* nodeCachedDataDir?: string
|
||||
* }} */
|
||||
const configuration = JSON.parse(args['config'] || '{}') || {};
|
||||
* @param {string[]} modulePaths
|
||||
* @param {(result, configuration: object) => any} resultCallback
|
||||
* @param {{ forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options
|
||||
*/
|
||||
function load(modulePaths, resultCallback, options) {
|
||||
const args = parseURLQueryArgs();
|
||||
/**
|
||||
* // configuration: INativeWindowConfiguration
|
||||
* @type {{
|
||||
* zoomLevel?: number,
|
||||
* extensionDevelopmentPath?: string[],
|
||||
* extensionTestsPath?: string,
|
||||
* userEnv?: { [key: string]: string | undefined },
|
||||
* appRoot?: string,
|
||||
* nodeCachedDataDir?: string
|
||||
* }} */
|
||||
const configuration = JSON.parse(args['config'] || '{}') || {};
|
||||
|
||||
// Apply zoom level early to avoid glitches
|
||||
const zoomLevel = configuration.zoomLevel;
|
||||
if (typeof zoomLevel === 'number' && zoomLevel !== 0) {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
// Apply zoom level early to avoid glitches
|
||||
const zoomLevel = configuration.zoomLevel;
|
||||
if (typeof zoomLevel === 'number' && zoomLevel !== 0) {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
}
|
||||
|
||||
// Error handler
|
||||
process.on('uncaughtException', function (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
});
|
||||
|
||||
// Developer tools
|
||||
const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath;
|
||||
let developerToolsUnbind;
|
||||
if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) {
|
||||
developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding);
|
||||
}
|
||||
|
||||
// Correctly inherit the parent's environment
|
||||
Object.assign(process.env, configuration.userEnv);
|
||||
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport(path.join(configuration.appRoot, 'node_modules'));
|
||||
|
||||
if (options && typeof options.canModifyDOM === 'function') {
|
||||
options.canModifyDOM(configuration);
|
||||
}
|
||||
|
||||
// Get the nls configuration into the process.env as early as possible.
|
||||
const nlsConfig = bootstrap.setupNLS();
|
||||
|
||||
let locale = nlsConfig.availableLanguages['*'] || 'en';
|
||||
if (locale === 'zh-tw') {
|
||||
locale = 'zh-Hant';
|
||||
} else if (locale === 'zh-cn') {
|
||||
locale = 'zh-Hans';
|
||||
}
|
||||
|
||||
window.document.documentElement.setAttribute('lang', locale);
|
||||
|
||||
// do not advertise AMD to avoid confusing UMD modules loaded with nodejs
|
||||
window['define'] = undefined;
|
||||
|
||||
// replace the patched electron fs with the original node fs for all AMD code
|
||||
require.define('fs', ['original-fs'], function (originalFS) { return originalFS; });
|
||||
|
||||
window['MonacoEnvironment'] = {};
|
||||
|
||||
const loaderConfig = {
|
||||
baseUrl: `${bootstrap.uriFromPath(configuration.appRoot)}/out`,
|
||||
'vs/nls': nlsConfig,
|
||||
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
|
||||
};
|
||||
|
||||
loaderConfig.nodeModules = loaderConfig.nodeModules.concat([
|
||||
'@angular/common',
|
||||
'@angular/core',
|
||||
'@angular/forms',
|
||||
'@angular/platform-browser',
|
||||
'@angular/platform-browser-dynamic',
|
||||
'@angular/router',
|
||||
'rxjs/Observable',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer',
|
||||
'slickgrid/lib/jquery.event.drag-2.3.0',
|
||||
'slickgrid/lib/jquery-ui-1.9.2',
|
||||
'slickgrid/slick.core',
|
||||
'slickgrid/slick.grid',
|
||||
'slickgrid/slick.editors',
|
||||
'slickgrid/slick.dataview'
|
||||
]);
|
||||
|
||||
// cached data config
|
||||
if (configuration.nodeCachedDataDir) {
|
||||
loaderConfig.nodeCachedData = {
|
||||
path: configuration.nodeCachedDataDir,
|
||||
seed: modulePaths.join('')
|
||||
};
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeLoaderConfig === 'function') {
|
||||
options.beforeLoaderConfig(configuration, loaderConfig);
|
||||
}
|
||||
|
||||
require.config(loaderConfig);
|
||||
|
||||
if (nlsConfig.pseudo) {
|
||||
require(['vs/nls'], function (nlsPlugin) {
|
||||
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
|
||||
});
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeRequire === 'function') {
|
||||
options.beforeRequire();
|
||||
}
|
||||
|
||||
require(modulePaths, result => {
|
||||
try {
|
||||
const callbackResult = resultCallback(result, configuration);
|
||||
if (callbackResult && typeof callbackResult.then === 'function') {
|
||||
callbackResult.then(() => {
|
||||
if (developerToolsUnbind && options && options.removeDeveloperKeybindingsAfterLoad) {
|
||||
developerToolsUnbind();
|
||||
}
|
||||
}, error => {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
}
|
||||
}, onUnexpectedError);
|
||||
}
|
||||
|
||||
// Error handler
|
||||
process.on('uncaughtException', function (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
});
|
||||
/**
|
||||
* @returns {{[param: string]: string }}
|
||||
*/
|
||||
function parseURLQueryArgs() {
|
||||
const search = window.location.search || '';
|
||||
|
||||
// Developer tools
|
||||
const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath;
|
||||
let developerToolsUnbind;
|
||||
if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) {
|
||||
developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding);
|
||||
return 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; }, {});
|
||||
}
|
||||
|
||||
// Correctly inherit the parent's environment
|
||||
exports.assign(process.env, configuration.userEnv);
|
||||
/**
|
||||
* @param {boolean} disallowReloadKeybinding
|
||||
* @returns {() => void}
|
||||
*/
|
||||
function registerDeveloperKeybindings(disallowReloadKeybinding) {
|
||||
const extractKey = function (e) {
|
||||
return [
|
||||
e.ctrlKey ? 'ctrl-' : '',
|
||||
e.metaKey ? 'meta-' : '',
|
||||
e.altKey ? 'alt-' : '',
|
||||
e.shiftKey ? 'shift-' : '',
|
||||
e.keyCode
|
||||
].join('');
|
||||
};
|
||||
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport(path.join(configuration.appRoot, 'node_modules'));
|
||||
// Devtools & reload support
|
||||
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
|
||||
const TOGGLE_DEV_TOOLS_KB_ALT = '123'; // F12
|
||||
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
|
||||
|
||||
if (options && typeof options.canModifyDOM === 'function') {
|
||||
options.canModifyDOM(configuration);
|
||||
}
|
||||
let listener = function (e) {
|
||||
const key = extractKey(e);
|
||||
if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {
|
||||
ipc.send('vscode:toggleDevTools');
|
||||
} else if (key === RELOAD_KB && !disallowReloadKeybinding) {
|
||||
ipc.send('vscode:reloadWindow');
|
||||
}
|
||||
};
|
||||
|
||||
// Get the nls configuration into the process.env as early as possible.
|
||||
const nlsConfig = bootstrap.setupNLS();
|
||||
window.addEventListener('keydown', listener);
|
||||
|
||||
let locale = nlsConfig.availableLanguages['*'] || 'en';
|
||||
if (locale === 'zh-tw') {
|
||||
locale = 'zh-Hant';
|
||||
} else if (locale === 'zh-cn') {
|
||||
locale = 'zh-Hans';
|
||||
}
|
||||
|
||||
window.document.documentElement.setAttribute('lang', locale);
|
||||
|
||||
// Load the loader
|
||||
const amdLoader = require(configuration.appRoot + '/out/vs/loader.js');
|
||||
const amdRequire = amdLoader.require;
|
||||
const amdDefine = amdLoader.require.define;
|
||||
const nodeRequire = amdLoader.require.nodeRequire;
|
||||
|
||||
window['nodeRequire'] = nodeRequire;
|
||||
window['require'] = amdRequire;
|
||||
|
||||
// replace the patched electron fs with the original node fs for all AMD code
|
||||
amdDefine('fs', ['original-fs'], function (originalFS) { return originalFS; });
|
||||
|
||||
window['MonacoEnvironment'] = {};
|
||||
|
||||
const loaderConfig = {
|
||||
baseUrl: bootstrap.uriFromPath(configuration.appRoot) + '/out',
|
||||
'vs/nls': nlsConfig,
|
||||
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
|
||||
};
|
||||
|
||||
loaderConfig.nodeModules = loaderConfig.nodeModules.concat([
|
||||
'@angular/common',
|
||||
'@angular/core',
|
||||
'@angular/forms',
|
||||
'@angular/platform-browser',
|
||||
'@angular/platform-browser-dynamic',
|
||||
'@angular/router',
|
||||
'rxjs/Observable',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer',
|
||||
'slickgrid/lib/jquery.event.drag-2.3.0',
|
||||
'slickgrid/lib/jquery-ui-1.9.2',
|
||||
'slickgrid/slick.core',
|
||||
'slickgrid/slick.grid',
|
||||
'slickgrid/slick.editors',
|
||||
'slickgrid/slick.dataview'
|
||||
]);
|
||||
// {{SQL CARBON EDIT}} - End
|
||||
|
||||
// cached data config
|
||||
if (configuration.nodeCachedDataDir) {
|
||||
loaderConfig.nodeCachedData = {
|
||||
path: configuration.nodeCachedDataDir,
|
||||
seed: modulePaths.join('')
|
||||
return function () {
|
||||
if (listener) {
|
||||
window.removeEventListener('keydown', listener);
|
||||
listener = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeLoaderConfig === 'function') {
|
||||
options.beforeLoaderConfig(configuration, loaderConfig);
|
||||
}
|
||||
|
||||
amdRequire.config(loaderConfig);
|
||||
|
||||
if (nlsConfig.pseudo) {
|
||||
amdRequire(['vs/nls'], function (nlsPlugin) {
|
||||
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
|
||||
});
|
||||
}
|
||||
|
||||
if (options && typeof options.beforeRequire === 'function') {
|
||||
options.beforeRequire();
|
||||
}
|
||||
|
||||
amdRequire(modulePaths, result => {
|
||||
try {
|
||||
const callbackResult = resultCallback(result, configuration);
|
||||
if (callbackResult && typeof callbackResult.then === 'function') {
|
||||
callbackResult.then(() => {
|
||||
if (developerToolsUnbind && options && options.removeDeveloperKeybindingsAfterLoad) {
|
||||
developerToolsUnbind();
|
||||
}
|
||||
}, error => {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error, enableDeveloperTools);
|
||||
/**
|
||||
* @param {string | Error} error
|
||||
* @param {boolean} [enableDeveloperTools]
|
||||
*/
|
||||
function onUnexpectedError(error, enableDeveloperTools) {
|
||||
if (enableDeveloperTools) {
|
||||
ipc.send('vscode:openDevTools');
|
||||
}
|
||||
}, onUnexpectedError);
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {{[param: string]: string }}
|
||||
*/
|
||||
function parseURLQueryArgs() {
|
||||
const search = window.location.search || '';
|
||||
console.error(`[uncaught exception]: ${error}`);
|
||||
|
||||
return 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; }, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} disallowReloadKeybinding
|
||||
* @returns {() => void}
|
||||
*/
|
||||
function registerDeveloperKeybindings(disallowReloadKeybinding) {
|
||||
|
||||
const ipc = require('electron').ipcRenderer;
|
||||
|
||||
const extractKey = function (e) {
|
||||
return [
|
||||
e.ctrlKey ? 'ctrl-' : '',
|
||||
e.metaKey ? 'meta-' : '',
|
||||
e.altKey ? 'alt-' : '',
|
||||
e.shiftKey ? 'shift-' : '',
|
||||
e.keyCode
|
||||
].join('');
|
||||
};
|
||||
|
||||
// Devtools & reload support
|
||||
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
|
||||
const TOGGLE_DEV_TOOLS_KB_ALT = '123'; // F12
|
||||
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
|
||||
|
||||
let listener = function (e) {
|
||||
const key = extractKey(e);
|
||||
if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {
|
||||
ipc.send('vscode:toggleDevTools');
|
||||
} else if (key === RELOAD_KB && !disallowReloadKeybinding) {
|
||||
ipc.send('vscode:reloadWindow');
|
||||
if (error && typeof error !== 'string' && error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', listener);
|
||||
|
||||
return function () {
|
||||
if (listener) {
|
||||
window.removeEventListener('keydown', listener);
|
||||
listener = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | Error} error
|
||||
* @param {boolean} enableDeveloperTools
|
||||
*/
|
||||
function onUnexpectedError(error, enableDeveloperTools) {
|
||||
|
||||
const ipc = require('electron').ipcRenderer;
|
||||
|
||||
if (enableDeveloperTools) {
|
||||
ipc.send('vscode:openDevTools');
|
||||
}
|
||||
|
||||
console.error('[uncaught exception]: ' + error);
|
||||
|
||||
if (error && typeof error !== 'string' && error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
}
|
||||
return {
|
||||
load
|
||||
};
|
||||
}));
|
||||
|
||||
502
src/bootstrap.js
vendored
502
src/bootstrap.js
vendored
@@ -6,316 +6,254 @@
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
//#region global bootstrapping
|
||||
// Simple module style to support node.js and browser environments
|
||||
(function (globalThis, factory) {
|
||||
|
||||
// increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
|
||||
Error.stackTraceLimit = 100;
|
||||
|
||||
// Workaround for Electron not installing a handler to ignore SIGPIPE
|
||||
// (https://github.com/electron/electron/issues/13254)
|
||||
process.on('SIGPIPE', () => {
|
||||
console.error(new Error('Unexpected SIGPIPE'));
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Add support for redirecting the loading of node modules
|
||||
|
||||
exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
if (!injectPath) {
|
||||
throw new Error('Missing injectPath');
|
||||
// Node.js
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
}
|
||||
|
||||
// Browser
|
||||
else {
|
||||
globalThis.MonacoBootstrap = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
const Module = require('module');
|
||||
const path = require('path');
|
||||
|
||||
const nodeModulesPath = path.join(__dirname, '../node_modules');
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent) {
|
||||
const paths = originalResolveLookupPaths(moduleName, parent);
|
||||
if (Array.isArray(paths)) {
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === nodeModulesPath) {
|
||||
paths.splice(i, 0, injectPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Remove global paths from the node lookup paths
|
||||
|
||||
exports.removeGlobalNodeModuleLookupPaths = function () {
|
||||
const Module = require('module');
|
||||
// @ts-ignore
|
||||
const globalPaths = Module.globalPaths;
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent) {
|
||||
const paths = originalResolveLookupPaths(moduleName, parent);
|
||||
let commonSuffixLength = 0;
|
||||
while (commonSuffixLength < paths.length && paths[paths.length - 1 - commonSuffixLength] === globalPaths[globalPaths.length - 1 - commonSuffixLength]) {
|
||||
commonSuffixLength++;
|
||||
}
|
||||
return paths.slice(0, paths.length - commonSuffixLength);
|
||||
};
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Add support for using node_modules.asar
|
||||
|
||||
/**
|
||||
* @param {string=} nodeModulesPath
|
||||
*/
|
||||
exports.enableASARSupport = function (nodeModulesPath) {
|
||||
const Module = require('module');
|
||||
const path = require('path');
|
||||
|
||||
let NODE_MODULES_PATH = nodeModulesPath;
|
||||
if (!NODE_MODULES_PATH) {
|
||||
NODE_MODULES_PATH = path.join(__dirname, '../node_modules');
|
||||
}
|
||||
|
||||
const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (request, parent) {
|
||||
const paths = originalResolveLookupPaths(request, parent);
|
||||
if (Array.isArray(paths)) {
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === NODE_MODULES_PATH) {
|
||||
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region URI helpers
|
||||
|
||||
/**
|
||||
* @param {string} _path
|
||||
* @returns {string}
|
||||
*/
|
||||
exports.uriFromPath = function (_path) {
|
||||
const path = require('path');
|
||||
|
||||
let pathName = path.resolve(_path).replace(/\\/g, '/');
|
||||
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
|
||||
pathName = '/' + pathName;
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
let uri;
|
||||
if (process.platform === 'win32' && pathName.startsWith('//')) { // specially handle Windows UNC paths
|
||||
uri = encodeURI('file:' + pathName);
|
||||
} else {
|
||||
uri = encodeURI('file://' + pathName);
|
||||
}
|
||||
|
||||
return uri.replace(/#/g, '%23');
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region FS helpers
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
exports.readFile = function (file) {
|
||||
const fs = require('fs');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(file, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(data);
|
||||
});
|
||||
//#region global bootstrapping
|
||||
|
||||
// increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
|
||||
Error.stackTraceLimit = 100;
|
||||
|
||||
// Workaround for Electron not installing a handler to ignore SIGPIPE
|
||||
// (https://github.com/electron/electron/issues/13254)
|
||||
process.on('SIGPIPE', () => {
|
||||
console.error(new Error('Unexpected SIGPIPE'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @param {string} content
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.writeFile = function (file, content) {
|
||||
const fs = require('fs');
|
||||
//#endregion
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.writeFile(file, content, 'utf8', function (err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
|
||||
//#region Add support for using node_modules.asar
|
||||
|
||||
/**
|
||||
* @param {string=} nodeModulesPath
|
||||
*/
|
||||
function enableASARSupport(nodeModulesPath) {
|
||||
let NODE_MODULES_PATH = nodeModulesPath;
|
||||
if (!NODE_MODULES_PATH) {
|
||||
NODE_MODULES_PATH = path.join(__dirname, '../node_modules');
|
||||
} else {
|
||||
// use the drive letter casing of __dirname
|
||||
if (process.platform === 'win32') {
|
||||
NODE_MODULES_PATH = __dirname.substr(0, 1) + NODE_MODULES_PATH.substr(1);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} dir
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
exports.mkdirp = function mkdirp(dir) {
|
||||
const fs = require('fs');
|
||||
|
||||
return new Promise((c, e) => fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir)));
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region NLS helpers
|
||||
|
||||
/**
|
||||
* @returns {{locale?: string, availableLanguages: {[lang: string]: string;}, pseudo?: boolean }}
|
||||
*/
|
||||
exports.setupNLS = function () {
|
||||
const path = require('path');
|
||||
|
||||
// Get the nls configuration into the process.env as early as possible.
|
||||
let nlsConfig = { availableLanguages: {} };
|
||||
if (process.env['VSCODE_NLS_CONFIG']) {
|
||||
try {
|
||||
nlsConfig = JSON.parse(process.env['VSCODE_NLS_CONFIG']);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
||||
const bundles = Object.create(null);
|
||||
const NODE_MODULES_ASAR_PATH = `${NODE_MODULES_PATH}.asar`;
|
||||
|
||||
nlsConfig.loadBundle = function (bundle, language, cb) {
|
||||
const result = bundles[bundle];
|
||||
if (result) {
|
||||
cb(undefined, result);
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json');
|
||||
exports.readFile(bundleFile).then(function (content) {
|
||||
const json = JSON.parse(content);
|
||||
bundles[bundle] = json;
|
||||
|
||||
cb(undefined, json);
|
||||
}).catch((error) => {
|
||||
try {
|
||||
if (nlsConfig._corruptedFile) {
|
||||
exports.writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (request, parent) {
|
||||
const paths = originalResolveLookupPaths(request, parent);
|
||||
if (Array.isArray(paths)) {
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === NODE_MODULES_PATH) {
|
||||
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
cb(error, undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
}
|
||||
|
||||
return nlsConfig;
|
||||
};
|
||||
//#endregion
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Portable helpers
|
||||
//#region URI helpers
|
||||
|
||||
/**
|
||||
* @returns {{ portableDataPath: string, isPortable: boolean }}
|
||||
*/
|
||||
exports.configurePortable = function () {
|
||||
const product = require('../product.json');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const appRoot = path.dirname(__dirname);
|
||||
|
||||
function getApplicationPath() {
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
return appRoot;
|
||||
/**
|
||||
* @param {string} _path
|
||||
* @returns {string}
|
||||
*/
|
||||
function uriFromPath(_path) {
|
||||
let pathName = path.resolve(_path).replace(/\\/g, '/');
|
||||
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
|
||||
pathName = `/${pathName}`;
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
return path.dirname(path.dirname(path.dirname(appRoot)));
|
||||
}
|
||||
|
||||
return path.dirname(path.dirname(appRoot));
|
||||
}
|
||||
|
||||
function getPortableDataPath() {
|
||||
if (process.env['VSCODE_PORTABLE']) {
|
||||
return process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||
return path.join(getApplicationPath(), 'data');
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const portableDataName = product.portable || `${product.applicationName}-portable-data`;
|
||||
return path.join(path.dirname(getApplicationPath()), portableDataName);
|
||||
}
|
||||
|
||||
const portableDataPath = getPortableDataPath();
|
||||
const isPortable = !('target' in product) && fs.existsSync(portableDataPath);
|
||||
const portableTempPath = path.join(portableDataPath, 'tmp');
|
||||
const isTempPortable = isPortable && fs.existsSync(portableTempPath);
|
||||
|
||||
if (isPortable) {
|
||||
process.env['VSCODE_PORTABLE'] = portableDataPath;
|
||||
} else {
|
||||
delete process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
if (isTempPortable) {
|
||||
if (process.platform === 'win32') {
|
||||
process.env['TMP'] = portableTempPath;
|
||||
process.env['TEMP'] = portableTempPath;
|
||||
/** @type {string} */
|
||||
let uri;
|
||||
if (process.platform === 'win32' && pathName.startsWith('//')) { // specially handle Windows UNC paths
|
||||
uri = encodeURI(`file:${pathName}`);
|
||||
} else {
|
||||
process.env['TMPDIR'] = portableTempPath;
|
||||
uri = encodeURI(`file://${pathName}`);
|
||||
}
|
||||
|
||||
return uri.replace(/#/g, '%23');
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region NLS helpers
|
||||
|
||||
/**
|
||||
* @returns {{locale?: string, availableLanguages: {[lang: string]: string;}, pseudo?: boolean }}
|
||||
*/
|
||||
function setupNLS() {
|
||||
|
||||
// Get the nls configuration into the process.env as early as possible.
|
||||
let nlsConfig = { availableLanguages: {} };
|
||||
if (process.env['VSCODE_NLS_CONFIG']) {
|
||||
try {
|
||||
nlsConfig = JSON.parse(process.env['VSCODE_NLS_CONFIG']);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
||||
const bundles = Object.create(null);
|
||||
|
||||
nlsConfig.loadBundle = function (bundle, language, cb) {
|
||||
const result = bundles[bundle];
|
||||
if (result) {
|
||||
cb(undefined, result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, `${bundle.replace(/\//g, '!')}.nls.json`);
|
||||
readFile(bundleFile).then(function (content) {
|
||||
const json = JSON.parse(content);
|
||||
bundles[bundle] = json;
|
||||
|
||||
cb(undefined, json);
|
||||
}).catch((error) => {
|
||||
try {
|
||||
if (nlsConfig._corruptedFile) {
|
||||
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
|
||||
}
|
||||
} finally {
|
||||
cb(error, undefined);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return nlsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
function readFile(file) {
|
||||
return fs.promises.readFile(file, 'utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @param {string} content
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function writeFile(file, content) {
|
||||
return fs.promises.writeFile(file, content, 'utf8');
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region Portable helpers
|
||||
|
||||
/**
|
||||
* @param {{ portable: string; applicationName: string; }} product
|
||||
* @returns {{portableDataPath: string;isPortable: boolean;}}
|
||||
*/
|
||||
function configurePortable(product) {
|
||||
const appRoot = path.dirname(__dirname);
|
||||
|
||||
function getApplicationPath() {
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
return appRoot;
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
return path.dirname(path.dirname(path.dirname(appRoot)));
|
||||
}
|
||||
|
||||
return path.dirname(path.dirname(appRoot));
|
||||
}
|
||||
|
||||
function getPortableDataPath() {
|
||||
if (process.env['VSCODE_PORTABLE']) {
|
||||
return process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||
return path.join(getApplicationPath(), 'data');
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const portableDataName = product.portable || `${product.applicationName}-portable-data`;
|
||||
return path.join(path.dirname(getApplicationPath()), portableDataName);
|
||||
}
|
||||
|
||||
const portableDataPath = getPortableDataPath();
|
||||
const isPortable = !('target' in product) && fs.existsSync(portableDataPath);
|
||||
const portableTempPath = path.join(portableDataPath, 'tmp');
|
||||
const isTempPortable = isPortable && fs.existsSync(portableTempPath);
|
||||
|
||||
if (isPortable) {
|
||||
process.env['VSCODE_PORTABLE'] = portableDataPath;
|
||||
} else {
|
||||
delete process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
if (isTempPortable) {
|
||||
if (process.platform === 'win32') {
|
||||
process.env['TMP'] = portableTempPath;
|
||||
process.env['TEMP'] = portableTempPath;
|
||||
} else {
|
||||
process.env['TMPDIR'] = portableTempPath;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
portableDataPath,
|
||||
isPortable
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region ApplicationInsights
|
||||
|
||||
// Prevents appinsights from monkey patching modules.
|
||||
// This should be called before importing the applicationinsights module
|
||||
function avoidMonkeyPatchFromAppInsights() {
|
||||
// @ts-ignore
|
||||
process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] = true; // Skip monkey patching of 3rd party modules by appinsights
|
||||
global['diagnosticsSource'] = {}; // Prevents diagnostic channel (which patches "require") from initializing entirely
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
return {
|
||||
portableDataPath,
|
||||
isPortable
|
||||
enableASARSupport,
|
||||
avoidMonkeyPatchFromAppInsights,
|
||||
configurePortable,
|
||||
setupNLS,
|
||||
uriFromPath
|
||||
};
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region ApplicationInsights
|
||||
|
||||
// Prevents appinsights from monkey patching modules.
|
||||
// This should be called before importing the applicationinsights module
|
||||
exports.avoidMonkeyPatchFromAppInsights = function () {
|
||||
// @ts-ignore
|
||||
process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] = true; // Skip monkey patching of 3rd party modules by appinsights
|
||||
global['diagnosticsSource'] = {}; // Prevents diagnostic channel (which patches "require") from initializing entirely
|
||||
};
|
||||
|
||||
//#endregion
|
||||
}));
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
'use strict';
|
||||
|
||||
const bootstrap = require('./bootstrap');
|
||||
const product = require('../product.json');
|
||||
|
||||
// Avoid Monkey Patches from Application Insights
|
||||
bootstrap.avoidMonkeyPatchFromAppInsights();
|
||||
|
||||
// Enable portable support
|
||||
bootstrap.configurePortable();
|
||||
bootstrap.configurePortable(product);
|
||||
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport();
|
||||
|
||||
// Load CLI through AMD loader
|
||||
require('./bootstrap-amd').load('vs/code/node/cli');
|
||||
require('./bootstrap-amd').load('vs/code/node/cli');
|
||||
|
||||
19
src/main.js
19
src/main.js
@@ -21,7 +21,7 @@ const product = require('../product.json');
|
||||
const { app, protocol } = require('electron');
|
||||
|
||||
// Enable portable support
|
||||
const portable = bootstrap.configurePortable();
|
||||
const portable = bootstrap.configurePortable(product);
|
||||
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport();
|
||||
@@ -93,8 +93,9 @@ setCurrentWorkingDirectory();
|
||||
// Register custom schemes with privileges
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme: 'vscode-resource',
|
||||
scheme: 'vscode-webview',
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
supportFetchAPI: true,
|
||||
corsEnabled: true,
|
||||
@@ -473,7 +474,7 @@ function getNodeCachedDir() {
|
||||
|
||||
async ensureExists() {
|
||||
try {
|
||||
await bootstrap.mkdirp(this.value);
|
||||
await mkdirp(this.value);
|
||||
|
||||
return this.value;
|
||||
} catch (error) {
|
||||
@@ -502,6 +503,18 @@ function getNodeCachedDir() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} dir
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
function mkdirp(dir) {
|
||||
const fs = require('fs');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? reject(err) : resolve(dir));
|
||||
});
|
||||
}
|
||||
|
||||
//#region NLS Support
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,14 +69,4 @@ export class BrowserClipboardService implements IClipboardService {
|
||||
hasResources(): Promise<boolean> {
|
||||
return this._vsClipboardService.hasResources();
|
||||
}
|
||||
|
||||
readFindTextSync(): string {
|
||||
// eslint-disable-next-line no-sync
|
||||
return this._vsClipboardService.readFindTextSync();
|
||||
}
|
||||
|
||||
writeFindTextSync(text: string): void {
|
||||
// eslint-disable-next-line no-sync
|
||||
return this._vsClipboardService.writeFindTextSync(text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,14 @@ export class ExtHostModelViewTreeViews implements ExtHostModelViewTreeViewsShape
|
||||
$setVisible(treeViewId: string, visible: boolean): void {
|
||||
}
|
||||
|
||||
$hasResolve(treeViewId: string): Promise<boolean> {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
$resolve(treeViewId: string, treeItemHandle: string): Promise<ITreeComponentItem | undefined> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private createExtHostTreeViewer<T>(handle: number, id: string, dataProvider: azdata.TreeComponentDataProvider<T>, extension: IExtensionDescription, logService: ILogService): ExtHostTreeView<T> {
|
||||
const treeView = new ExtHostTreeView<T>(handle, id, dataProvider, this._proxy, undefined, extension, logService);
|
||||
this.treeViews.set(`${handle}-${id}`, treeView);
|
||||
|
||||
@@ -561,10 +561,10 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
||||
CardType: sqlExtHostTypes.CardType,
|
||||
Orientation: sqlExtHostTypes.Orientation,
|
||||
SqlThemeIcon: sqlExtHostTypes.SqlThemeIcon,
|
||||
TreeComponentItem: sqlExtHostTypes.TreeComponentItem,
|
||||
TreeComponentItem: sqlExtHostTypes.TreeComponentItem as any, // work around
|
||||
nb: nb,
|
||||
AzureResource: sqlExtHostTypes.AzureResource,
|
||||
TreeItem: sqlExtHostTypes.TreeItem,
|
||||
TreeItem: sqlExtHostTypes.TreeItem as any, // work around
|
||||
extensions: extensions,
|
||||
ColumnType: sqlExtHostTypes.ColumnType,
|
||||
ActionOnCellCheckboxCheck: sqlExtHostTypes.ActionOnCellCheckboxCheck,
|
||||
|
||||
@@ -732,6 +732,8 @@ export interface ExtHostModelViewTreeViewsShape {
|
||||
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
|
||||
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
|
||||
$setVisible(treeViewId: string, visible: boolean): void;
|
||||
$hasResolve(treeViewId: string): Promise<boolean>;
|
||||
$resolve(treeViewId: string, treeItemHandle: string): Promise<ITreeComponentItem | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostBackgroundTaskManagementShape {
|
||||
|
||||
@@ -397,7 +397,6 @@ export interface ToolbarLayout {
|
||||
}
|
||||
|
||||
export class TreeComponentItem extends vsExtTypes.TreeItem {
|
||||
label?: string;
|
||||
checked?: boolean;
|
||||
}
|
||||
|
||||
@@ -411,7 +410,6 @@ export enum AzureResource {
|
||||
}
|
||||
|
||||
export class TreeItem extends vsExtTypes.TreeItem {
|
||||
label?: string;
|
||||
payload?: IConnectionProfile;
|
||||
providerHandle?: string;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,14 @@ export class TreeView extends Disposable implements ITreeView {
|
||||
identityProvider: new TreeViewIdentityProvider(),
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
|
||||
if (element.accessibilityInformation) {
|
||||
return element.accessibilityInformation.label;
|
||||
}
|
||||
|
||||
return isString(element.tooltip) ? element.tooltip : element.label ? element.label.label : '';
|
||||
},
|
||||
getRole(element: ITreeItem): string | undefined {
|
||||
return element.accessibilityInformation?.role ?? 'treeitem';
|
||||
},
|
||||
getWidgetAriaLabel(): string {
|
||||
return widgetAriaLabel;
|
||||
@@ -842,7 +849,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
}) : undefined;
|
||||
const icon = this.themeService.getColorTheme().type === LIGHT ? node.icon : node.iconDark;
|
||||
const iconUrl = icon ? URI.revive(icon) : null;
|
||||
const title = node.tooltip ? node.tooltip : resource ? undefined : label;
|
||||
const title = node.tooltip ? isString(node.tooltip) ? node.tooltip : undefined : resource ? undefined : label;
|
||||
const sqlIcon = node.sqlIcon;
|
||||
|
||||
// reset
|
||||
|
||||
1
src/typings/require.d.ts
vendored
1
src/typings/require.d.ts
vendored
@@ -47,6 +47,7 @@ interface NodeRequire {
|
||||
onError: Function;
|
||||
__$__nodeRequire<T>(moduleName: string): T;
|
||||
getStats(): ReadonlyArray<LoaderEvent>;
|
||||
define(amdModuleId: string, dependencies: string[], callback: (...args: any[]) => any): any;
|
||||
}
|
||||
|
||||
declare var require: NodeRequire;
|
||||
|
||||
@@ -820,6 +820,7 @@ export function isHTMLElement(o: any): o is HTMLElement {
|
||||
export const EventType = {
|
||||
// Mouse
|
||||
CLICK: 'click',
|
||||
AUXCLICK: 'auxclick',
|
||||
DBLCLICK: 'dblclick',
|
||||
MOUSE_UP: 'mouseup',
|
||||
MOUSE_DOWN: 'mousedown',
|
||||
|
||||
@@ -19,4 +19,6 @@
|
||||
.monaco-count-badge.long {
|
||||
padding: 2px 3px;
|
||||
border-radius: 2px;
|
||||
min-height: auto;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.monaco-dialog-box .dialog-message-row > .codicon {
|
||||
.monaco-dialog-box .dialog-message-row > .dialog-icon.codicon {
|
||||
flex: 0 0 48px;
|
||||
height: 48px;
|
||||
align-self: baseline;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextViewProvider, IAnchor, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IMenuOptions } from 'vs/base/browser/ui/menu/menu';
|
||||
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { EventHelper, EventType, removeClass, addClass, append, $, addDisposableListener, addClasses } from 'vs/base/browser/dom';
|
||||
import { EventHelper, EventType, removeClass, addClass, append, $, addDisposableListener, addClasses, DOMEvent } from 'vs/base/browser/dom';
|
||||
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
@@ -122,7 +122,7 @@ export class BaseDropdown extends ActionRunner {
|
||||
return !!this.visible;
|
||||
}
|
||||
|
||||
protected onEvent(e: Event, activeElement: HTMLElement): void {
|
||||
protected onEvent(e: DOMEvent, activeElement: HTMLElement): void {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
@@ -294,6 +294,9 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
private anchorAlignmentProvider: (() => AnchorAlignment) | undefined;
|
||||
private menuAsChild?: boolean;
|
||||
|
||||
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
|
||||
|
||||
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
|
||||
@@ -339,7 +342,10 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
|
||||
this.dropdownMenu = this._register(new DropdownMenu(container, options));
|
||||
this._register(this.dropdownMenu.onDidChangeVisibility(visible => this.element?.setAttribute('aria-expanded', `${visible}`)));
|
||||
this._register(this.dropdownMenu.onDidChangeVisibility(visible => {
|
||||
this.element?.setAttribute('aria-expanded', `${visible}`);
|
||||
this._onDidChangeVisibility.fire(visible);
|
||||
}));
|
||||
|
||||
this.dropdownMenu.menuOptions = {
|
||||
actionViewItemProvider: this.actionViewItemProvider,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { tail2 as tail, equals } from 'vs/base/common/arrays';
|
||||
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions, IBoundarySashes } from './gridview';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview';
|
||||
export { Orientation, IViewSize, orthogonal, LayoutPriority } from './gridview';
|
||||
|
||||
export const enum Direction {
|
||||
Up,
|
||||
|
||||
@@ -376,6 +376,10 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
}
|
||||
|
||||
updateElementHeight(index: number, size: number, anchorIndex: number | null): void {
|
||||
if (index < 0 || index >= this.items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.items[index].size === size) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,10 +225,26 @@ class TraitSpliceable<T> implements ISpliceable<T> {
|
||||
}
|
||||
}
|
||||
|
||||
function isInputElement(e: HTMLElement): boolean {
|
||||
export function isInputElement(e: HTMLElement): boolean {
|
||||
return e.tagName === 'INPUT' || e.tagName === 'TEXTAREA';
|
||||
}
|
||||
|
||||
export function isMonacoEditor(e: HTMLElement): boolean {
|
||||
if (DOM.hasClass(e, 'monaco-editor')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DOM.hasClass(e, 'monaco-list')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.parentElement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isMonacoEditor(e.parentElement);
|
||||
}
|
||||
|
||||
class KeyboardController<T> implements IDisposable {
|
||||
|
||||
private readonly disposables = new DisposableStore();
|
||||
@@ -572,12 +588,20 @@ export class MouseController<T> implements IDisposable {
|
||||
}
|
||||
|
||||
private onMouseDown(e: IListMouseEvent<T> | IListTouchEvent<T>): void {
|
||||
if (isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.activeElement !== e.browserEvent.target) {
|
||||
this.list.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private onContextMenu(e: IListContextMenuEvent<T>): void {
|
||||
if (isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const focus = typeof e.index === 'undefined' ? [] : [e.index];
|
||||
this.list.setFocus(focus, e.browserEvent);
|
||||
}
|
||||
@@ -587,7 +611,7 @@ export class MouseController<T> implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement)) {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -621,7 +645,7 @@ export class MouseController<T> implements IDisposable {
|
||||
}
|
||||
|
||||
protected onDoubleClick(e: IListMouseEvent<T>): void {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement)) {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -942,7 +942,6 @@ export class MenuBar extends Disposable {
|
||||
menuHolder.style.top = `0px`;
|
||||
menuHolder.style.right = `${this.container.clientWidth}px`;
|
||||
menuHolder.style.left = 'auto';
|
||||
console.log(customMenu.buttonElement.getBoundingClientRect().right - this.container.clientWidth);
|
||||
} else {
|
||||
menuHolder.style.top = `${this.container.clientHeight}px`;
|
||||
menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left}px`;
|
||||
|
||||
@@ -12,3 +12,16 @@
|
||||
font-weight: normal;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/** Actions */
|
||||
|
||||
.monaco-workbench .monaco-action-bar .action-item.select-container {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-action-bar .action-item .monaco-select-box {
|
||||
cursor: pointer;
|
||||
min-width: 110px;
|
||||
min-height: 18px;
|
||||
padding: 2px 23px 2px 8px;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IContextMenuProvider, DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export const CONTEXT = 'context.toolbar';
|
||||
|
||||
@@ -35,17 +36,21 @@ export class ToolBar extends Disposable {
|
||||
private options: IToolBarOptions;
|
||||
private actionBar: ActionBar;
|
||||
private toggleMenuAction: ToggleMenuAction;
|
||||
private toggleMenuActionViewItem = this._register(new MutableDisposable<DropdownMenuActionViewItem>());
|
||||
private toggleMenuActionViewItem: DropdownMenuActionViewItem | undefined;
|
||||
private toggleMenuActionViewItemDisposable: IDisposable = Disposable.None;
|
||||
private hasSecondaryActions: boolean = false;
|
||||
private lookupKeybindings: boolean;
|
||||
|
||||
private _onDidChangeDropdownVisibility = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeDropdownVisibility = this._onDidChangeDropdownVisibility.event;
|
||||
|
||||
constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
this.lookupKeybindings = typeof this.options.getKeyBinding === 'function';
|
||||
|
||||
this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionViewItem.value && this.toggleMenuActionViewItem.value.show(), options.toggleMenuTitle));
|
||||
this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionViewItem?.show(), options.toggleMenuTitle));
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.className = 'monaco-toolbar';
|
||||
@@ -60,8 +65,10 @@ export class ToolBar extends Disposable {
|
||||
// Return special action item for the toggle menu action
|
||||
if (action.id === ToggleMenuAction.ID) {
|
||||
|
||||
this.toggleMenuActionViewItemDisposable.dispose();
|
||||
|
||||
// Create new
|
||||
this.toggleMenuActionViewItem.value = new DropdownMenuActionViewItem(
|
||||
this.toggleMenuActionViewItem = new DropdownMenuActionViewItem(
|
||||
action,
|
||||
(<ToggleMenuAction>action).menuActions,
|
||||
contextMenuProvider,
|
||||
@@ -72,9 +79,14 @@ export class ToolBar extends Disposable {
|
||||
this.options.anchorAlignmentProvider,
|
||||
true
|
||||
);
|
||||
this.toggleMenuActionViewItem.value.setActionContext(this.actionBar.context);
|
||||
this.toggleMenuActionViewItem.setActionContext(this.actionBar.context);
|
||||
|
||||
return this.toggleMenuActionViewItem.value;
|
||||
this.toggleMenuActionViewItemDisposable = combinedDisposable(
|
||||
this.toggleMenuActionViewItem,
|
||||
this.toggleMenuActionViewItem.onDidChangeVisibility(e => this._onDidChangeDropdownVisibility.fire(e))
|
||||
);
|
||||
|
||||
return this.toggleMenuActionViewItem;
|
||||
}
|
||||
|
||||
return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined;
|
||||
@@ -92,8 +104,8 @@ export class ToolBar extends Disposable {
|
||||
|
||||
set context(context: unknown) {
|
||||
this.actionBar.context = context;
|
||||
if (this.toggleMenuActionViewItem.value) {
|
||||
this.toggleMenuActionViewItem.value.setActionContext(context);
|
||||
if (this.toggleMenuActionViewItem) {
|
||||
this.toggleMenuActionViewItem.setActionContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,23 +125,21 @@ export class ToolBar extends Disposable {
|
||||
this.actionBar.setAriaLabel(label);
|
||||
}
|
||||
|
||||
setActions(primaryActions: ReadonlyArray<IAction>, secondaryActions?: ReadonlyArray<IAction>): () => void {
|
||||
return () => {
|
||||
let primaryActionsToSet = primaryActions ? primaryActions.slice(0) : [];
|
||||
setActions(primaryActions: ReadonlyArray<IAction>, secondaryActions?: ReadonlyArray<IAction>): void {
|
||||
let primaryActionsToSet = primaryActions ? primaryActions.slice(0) : [];
|
||||
|
||||
// Inject additional action to open secondary actions if present
|
||||
this.hasSecondaryActions = !!(secondaryActions && secondaryActions.length > 0);
|
||||
if (this.hasSecondaryActions && secondaryActions) {
|
||||
this.toggleMenuAction.menuActions = secondaryActions.slice(0);
|
||||
primaryActionsToSet.push(this.toggleMenuAction);
|
||||
}
|
||||
// Inject additional action to open secondary actions if present
|
||||
this.hasSecondaryActions = !!(secondaryActions && secondaryActions.length > 0);
|
||||
if (this.hasSecondaryActions && secondaryActions) {
|
||||
this.toggleMenuAction.menuActions = secondaryActions.slice(0);
|
||||
primaryActionsToSet.push(this.toggleMenuAction);
|
||||
}
|
||||
|
||||
this.actionBar.clear();
|
||||
this.actionBar.clear();
|
||||
|
||||
primaryActionsToSet.forEach(action => {
|
||||
this.actionBar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) });
|
||||
});
|
||||
};
|
||||
primaryActionsToSet.forEach(action => {
|
||||
this.actionBar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) });
|
||||
});
|
||||
}
|
||||
|
||||
private getKeybindingLabel(action: IAction): string | undefined {
|
||||
@@ -153,6 +163,11 @@ export class ToolBar extends Disposable {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this.toggleMenuActionViewItemDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ToggleMenuAction extends Action {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/tree';
|
||||
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate, isInputElement, isMonacoEditor } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode, addClasses, removeClasses } from 'vs/base/browser/dom';
|
||||
import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';
|
||||
@@ -917,10 +917,6 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
function isInputElement(e: HTMLElement): boolean {
|
||||
return e.tagName === 'INPUT' || e.tagName === 'TEXTAREA';
|
||||
}
|
||||
|
||||
function asTreeMouseEvent<T>(event: IListMouseEvent<ITreeNode<T, any>>): ITreeMouseEvent<T> {
|
||||
let target: TreeMouseEventTarget = TreeMouseEventTarget.Unknown;
|
||||
|
||||
@@ -1084,7 +1080,7 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
||||
}
|
||||
|
||||
protected onViewPointer(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement)) {
|
||||
if (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
// Exported only for test reasons, do not use directly
|
||||
export interface ICompressedTreeElement<T> extends ITreeElement<T> {
|
||||
@@ -126,7 +126,7 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
|
||||
|
||||
constructor(
|
||||
private user: string,
|
||||
list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>,
|
||||
list: IList<ITreeNode<ICompressedTreeNode<T>, TFilterData>>,
|
||||
options: ICompressedObjectTreeModelOptions<T, TFilterData> = {}
|
||||
) {
|
||||
this.model = new ObjectTreeModel(user, list, options);
|
||||
@@ -290,6 +290,16 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
|
||||
this.model.rerender(compressedNode);
|
||||
}
|
||||
|
||||
updateElementHeight(element: T, height: number): void {
|
||||
const compressedNode = this.getCompressedNode(element);
|
||||
|
||||
if (!compressedNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.updateElementHeight(compressedNode, height);
|
||||
}
|
||||
|
||||
refilter(): void {
|
||||
this.model.refilter();
|
||||
}
|
||||
@@ -340,10 +350,13 @@ class CompressedTreeNodeWrapper<T, TFilterData> implements ITreeNode<T | null, T
|
||||
) { }
|
||||
}
|
||||
|
||||
function mapList<T, TFilterData>(nodeMapper: CompressedNodeWeakMapper<T, TFilterData>, list: ISpliceable<ITreeNode<T, TFilterData>>): ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>> {
|
||||
function mapList<T, TFilterData>(nodeMapper: CompressedNodeWeakMapper<T, TFilterData>, list: IList<ITreeNode<T, TFilterData>>): IList<ITreeNode<ICompressedTreeNode<T>, TFilterData>> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, toInsert: ITreeNode<ICompressedTreeNode<T>, TFilterData>[]): void {
|
||||
list.splice(start, deleteCount, toInsert.map(node => nodeMapper.map(node)) as ITreeNode<T, TFilterData>[]);
|
||||
},
|
||||
updateElementHeight(index: number, height: number): void {
|
||||
list.updateElementHeight(index, height);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -402,7 +415,7 @@ export class CompressibleObjectTreeModel<T extends NonNullable<any>, TFilterData
|
||||
|
||||
constructor(
|
||||
user: string,
|
||||
list: ISpliceable<ITreeNode<T, TFilterData>>,
|
||||
list: IList<ITreeNode<T, TFilterData>>,
|
||||
options: ICompressibleObjectTreeModelOptions<T, TFilterData> = {}
|
||||
) {
|
||||
this.elementMapper = options.elementMapper || DefaultElementMapper;
|
||||
@@ -492,6 +505,10 @@ export class CompressibleObjectTreeModel<T extends NonNullable<any>, TFilterData
|
||||
return this.model.rerender(location);
|
||||
}
|
||||
|
||||
updateElementHeight(element: T, height: number): void {
|
||||
this.model.updateElementHeight(element, height);
|
||||
}
|
||||
|
||||
refilter(): void {
|
||||
return this.model.refilter();
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, IDataSource, TreeError } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
export interface IDataTreeOptions<T, TFilterData = void> extends IAbstractTreeOptions<T, TFilterData> {
|
||||
readonly sorter?: ITreeSorter<T>;
|
||||
@@ -171,7 +171,7 @@ export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | nu
|
||||
return { elements, size: children.length };
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: ISpliceable<ITreeNode<T, TFilterData>>, options: IDataTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
protected createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: IDataTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
return new ObjectTreeModel(user, view, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
import 'vs/css!./media/tree';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IndexTreeModel } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { IndexTreeModel, IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { ITreeElement, ITreeModel, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
|
||||
@@ -41,7 +40,11 @@ export class IndexTree<T, TFilterData = void> extends AbstractTree<T, TFilterDat
|
||||
this.model.rerender(location);
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: ISpliceable<ITreeNode<T, TFilterData>>, options: IIndexTreeOptions<T, TFilterData>): ITreeModel<T, TFilterData, number[]> {
|
||||
updateElementHeight(location: number[], height: number): void {
|
||||
this.model.updateElementHeight(location, height);
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: IIndexTreeOptions<T, TFilterData>): ITreeModel<T, TFilterData, number[]> {
|
||||
return new IndexTreeModel(user, view, this.rootElement, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ function isCollapsibleStateUpdate(update: CollapseStateUpdate): update is Collap
|
||||
return typeof (update as any).collapsible === 'boolean';
|
||||
}
|
||||
|
||||
export interface IList<T> extends ISpliceable<T> {
|
||||
updateElementHeight(index: number, height: number): void;
|
||||
}
|
||||
|
||||
export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = void> implements ITreeModel<T, TFilterData, number[]> {
|
||||
|
||||
readonly rootRef = [];
|
||||
@@ -78,7 +82,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
|
||||
|
||||
constructor(
|
||||
private user: string,
|
||||
private list: ISpliceable<ITreeNode<T, TFilterData>>,
|
||||
private list: IList<ITreeNode<T, TFilterData>>,
|
||||
rootElement: T,
|
||||
options: IIndexTreeModelOptions<T, TFilterData> = {}
|
||||
) {
|
||||
@@ -212,6 +216,15 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
|
||||
}
|
||||
}
|
||||
|
||||
updateElementHeight(location: number[], height: number): void {
|
||||
if (location.length === 0) {
|
||||
throw new TreeError(this.user, 'Invalid tree location');
|
||||
}
|
||||
|
||||
const { listIndex } = this.getTreeNodeWithListIndex(location);
|
||||
this.list.updateElementHeight(listIndex, height);
|
||||
}
|
||||
|
||||
has(location: number[]): boolean {
|
||||
return this.hasTreeNode(location);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { AbstractTree, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IListVirtualDelegate, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { CompressibleObjectTreeModel, ElementMapper, ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
export interface IObjectTreeOptions<T, TFilterData = void> extends IAbstractTreeOptions<T, TFilterData> {
|
||||
readonly sorter?: ITreeSorter<T>;
|
||||
@@ -46,6 +46,10 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
|
||||
this.model.rerender(element);
|
||||
}
|
||||
|
||||
updateElementHeight(element: T, height: number): void {
|
||||
this.model.updateElementHeight(element, height);
|
||||
}
|
||||
|
||||
resort(element: T, recursive = true): void {
|
||||
this.model.resort(element, recursive);
|
||||
}
|
||||
@@ -54,7 +58,7 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
|
||||
return this.model.has(element);
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: ISpliceable<ITreeNode<T, TFilterData>>, options: IObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
protected createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: IObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
return new ObjectTreeModel(user, view, options);
|
||||
}
|
||||
}
|
||||
@@ -188,7 +192,7 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
|
||||
this.model.setChildren(element, children);
|
||||
}
|
||||
|
||||
protected createModel(user: string, view: ISpliceable<ITreeNode<T, TFilterData>>, options: ICompressibleObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
protected createModel(user: string, view: IList<ITreeNode<T, TFilterData>>, options: ICompressibleObjectTreeOptions<T, TFilterData>): ITreeModel<T | null, TFilterData, T | null> {
|
||||
return new CompressibleObjectTreeModel(user, view, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { IndexTreeModel, IIndexTreeModelOptions, IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
@@ -16,6 +15,7 @@ export type ITreeNodeCallback<T, TFilterData> = (node: ITreeNode<T, TFilterData>
|
||||
export interface IObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> extends ITreeModel<T | null, TFilterData, T | null> {
|
||||
setChildren(element: T | null, children: Iterable<ITreeElement<T>> | undefined): void;
|
||||
resort(element?: T | null, recursive?: boolean): void;
|
||||
updateElementHeight(element: T, height: number): void;
|
||||
}
|
||||
|
||||
export interface IObjectTreeModelOptions<T, TFilterData> extends IIndexTreeModelOptions<T, TFilterData> {
|
||||
@@ -41,7 +41,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
|
||||
constructor(
|
||||
private user: string,
|
||||
list: ISpliceable<ITreeNode<T, TFilterData>>,
|
||||
list: IList<ITreeNode<T, TFilterData>>,
|
||||
options: IObjectTreeModelOptions<T, TFilterData> = {}
|
||||
) {
|
||||
this.model = new IndexTreeModel(user, list, null, options);
|
||||
@@ -169,6 +169,11 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
this.model.rerender(location);
|
||||
}
|
||||
|
||||
updateElementHeight(element: T, height: number): void {
|
||||
const location = this.getElementLocation(element);
|
||||
this.model.updateElementHeight(location, height);
|
||||
}
|
||||
|
||||
resort(element: T | null = null, recursive = true): void {
|
||||
if (!this.sorter) {
|
||||
return;
|
||||
|
||||
@@ -62,6 +62,14 @@ export namespace Schemas {
|
||||
|
||||
export const webviewPanel = 'webview-panel';
|
||||
|
||||
/**
|
||||
* Scheme used for loading the wrapper html and script in webviews.
|
||||
*/
|
||||
export const vscodeWebview = 'vscode-webview';
|
||||
|
||||
/**
|
||||
* Scheme used for loading resources inside of webviews.
|
||||
*/
|
||||
export const vscodeWebviewResource = 'vscode-webview-resource';
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,7 +54,7 @@ if (typeof navigator === 'object' && !isElectronRenderer) {
|
||||
_userAgent = navigator.userAgent;
|
||||
_isWindows = _userAgent.indexOf('Windows') >= 0;
|
||||
_isMacintosh = _userAgent.indexOf('Macintosh') >= 0;
|
||||
_isIOS = _userAgent.indexOf('Macintosh') >= 0 && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;
|
||||
_isIOS = (_userAgent.indexOf('Macintosh') >= 0 || _userAgent.indexOf('iPad') >= 0 || _userAgent.indexOf('iPhone') >= 0) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;
|
||||
_isLinux = _userAgent.indexOf('Linux') >= 0;
|
||||
_isWeb = true;
|
||||
_locale = navigator.language;
|
||||
@@ -208,7 +208,7 @@ export const enum OperatingSystem {
|
||||
Macintosh = 2,
|
||||
Linux = 3
|
||||
}
|
||||
export const OS = (_isMacintosh ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux));
|
||||
export const OS = (_isMacintosh || _isIOS ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux));
|
||||
|
||||
let _isLittleEndian = true;
|
||||
let _isLittleEndianComputed = false;
|
||||
|
||||
@@ -18,7 +18,7 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa
|
||||
return pattern.toUpperCase();
|
||||
} else if (matches[0].toLowerCase() === matches[0]) {
|
||||
return pattern.toLowerCase();
|
||||
} else if (strings.containsUppercaseCharacter(matches[0][0])) {
|
||||
} else if (strings.containsUppercaseCharacter(matches[0][0]) && pattern.length > 0) {
|
||||
return pattern[0].toUpperCase() + pattern.substr(1);
|
||||
} else {
|
||||
// we don't understand its pattern yet.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export interface ISplice<T> {
|
||||
readonly start: number;
|
||||
@@ -32,3 +33,26 @@ export class Sequence<T> implements ISequence<T>, ISpliceable<T> {
|
||||
this._onDidSplice.fire({ start, deleteCount, toInsert });
|
||||
}
|
||||
}
|
||||
|
||||
export class SimpleSequence<T> implements ISequence<T> {
|
||||
|
||||
private _elements: T[];
|
||||
get elements(): T[] { return this._elements; }
|
||||
|
||||
readonly onDidSplice: Event<ISplice<T>>;
|
||||
private disposable: IDisposable;
|
||||
|
||||
constructor(elements: T[], onDidAdd: Event<T>, onDidRemove: Event<T>) {
|
||||
this._elements = [...elements];
|
||||
this.onDidSplice = Event.any(
|
||||
Event.map(onDidAdd, e => ({ start: this.elements.length, deleteCount: 0, toInsert: [e] })),
|
||||
Event.map(Event.filter(Event.map(onDidRemove, e => this.elements.indexOf(e)), i => i > -1), i => ({ start: i, deleteCount: 1, toInsert: [] }))
|
||||
);
|
||||
|
||||
this.disposable = this.onDidSplice(({ start, deleteCount, toInsert }) => this._elements.splice(start, deleteCount, ...toInsert));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* This code is also used by standalone cli's. Avoid adding dependencies to keep the size of the cli small.
|
||||
*/
|
||||
import { exec } from 'child_process';
|
||||
import * as os from 'os';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
const windowsTerminalEncodings = {
|
||||
'437': 'cp437', // United States
|
||||
@@ -39,7 +39,6 @@ const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
|
||||
|
||||
const UTF8 = 'utf8';
|
||||
|
||||
|
||||
export async function resolveTerminalEncoding(verbose?: boolean): Promise<string> {
|
||||
let rawEncodingPromise: Promise<string>;
|
||||
|
||||
@@ -54,7 +53,7 @@ export async function resolveTerminalEncoding(verbose?: boolean): Promise<string
|
||||
}
|
||||
|
||||
// Windows: educated guess
|
||||
else if (os.platform() === 'win32') {
|
||||
else if (isWindows) {
|
||||
rawEncodingPromise = new Promise<string>(resolve => {
|
||||
if (verbose) {
|
||||
console.log('Running "chcp" to detect terminal encoding...');
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
vertical-align: middle;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
min-height: auto;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.quick-input-action {
|
||||
|
||||
@@ -353,10 +353,12 @@ class QuickInput extends Disposable implements IQuickInput {
|
||||
this.ui.inputBox.showDecoration(severity);
|
||||
if (severity === Severity.Error) {
|
||||
const styles = this.ui.inputBox.stylesForType(severity);
|
||||
this.ui.message.style.color = styles.foreground ? `${styles.foreground}` : '';
|
||||
this.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : '';
|
||||
this.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : '';
|
||||
this.ui.message.style.paddingBottom = '4px';
|
||||
} else {
|
||||
this.ui.message.style.color = '';
|
||||
this.ui.message.style.backgroundColor = '';
|
||||
this.ui.message.style.border = '';
|
||||
this.ui.message.style.paddingBottom = '';
|
||||
|
||||
@@ -21,7 +21,7 @@ export function request(options: IRequestOptions, token: CancellationToken): Pro
|
||||
setRequestHeaders(xhr, options);
|
||||
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onerror = e => reject(new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText)));
|
||||
xhr.onerror = e => reject(new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText) || 'XHR failed'));
|
||||
xhr.onload = (e) => {
|
||||
resolve({
|
||||
res: {
|
||||
|
||||
@@ -247,3 +247,37 @@ export interface FileFilter {
|
||||
extensions: string[];
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface InputEvent {
|
||||
|
||||
// Docs: http://electronjs.org/docs/api/structures/input-event
|
||||
|
||||
/**
|
||||
* An array of modifiers of the event, can be `shift`, `control`, `alt`, `meta`,
|
||||
* `isKeypad`, `isAutoRepeat`, `leftButtonDown`, `middleButtonDown`,
|
||||
* `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`.
|
||||
*/
|
||||
modifiers: Array<'shift' | 'control' | 'alt' | 'meta' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right'>;
|
||||
}
|
||||
|
||||
export interface MouseInputEvent extends InputEvent {
|
||||
|
||||
// Docs: http://electronjs.org/docs/api/structures/mouse-input-event
|
||||
|
||||
/**
|
||||
* The button pressed, can be `left`, `middle`, `right`.
|
||||
*/
|
||||
button?: ('left' | 'middle' | 'right');
|
||||
clickCount?: number;
|
||||
globalX?: number;
|
||||
globalY?: number;
|
||||
movementX?: number;
|
||||
movementY?: number;
|
||||
/**
|
||||
* The type of the event, can be `mouseDown`, `mouseUp`, `mouseEnter`,
|
||||
* `mouseLeave`, `contextMenu`, `mouseWheel` or `mouseMove`.
|
||||
*/
|
||||
type: ('mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove');
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
interface IResolvedCompressedTreeElement<T> extends ICompressedTreeElement<T> {
|
||||
readonly element: T;
|
||||
@@ -289,11 +289,12 @@ suite('CompressedObjectTree', function () {
|
||||
});
|
||||
});
|
||||
|
||||
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
}
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -305,7 +306,7 @@ suite('CompressedObjectTree', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
assert.equal(model.size, 0);
|
||||
@@ -313,7 +314,7 @@ suite('CompressedObjectTree', function () {
|
||||
|
||||
test('flat', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0 },
|
||||
@@ -340,7 +341,7 @@ suite('CompressedObjectTree', function () {
|
||||
|
||||
test('nested', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
@@ -376,7 +377,7 @@ suite('CompressedObjectTree', function () {
|
||||
|
||||
test('compressed', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IndexTreeModel, IIndexTreeNode } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { IndexTreeModel, IIndexTreeNode, IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
}
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
});
|
||||
|
||||
test('insert', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 0 },
|
||||
@@ -53,7 +53,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('deep insert', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -90,7 +90,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('deep insert collapsed', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -118,7 +118,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('delete', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 0 },
|
||||
@@ -143,7 +143,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('nested delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -177,7 +177,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('deep delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -205,7 +205,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('hidden delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -230,7 +230,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('collapse', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -261,7 +261,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('expand', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -301,7 +301,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('collapse should recursively adjust visible count', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -334,7 +334,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('setCollapsible', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -403,7 +403,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -437,7 +437,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -460,7 +460,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -499,7 +499,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -545,7 +545,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -591,7 +591,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -639,7 +639,7 @@ suite('IndexTreeModel', function () {
|
||||
|
||||
test('simple', function () {
|
||||
const list: IIndexTreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -669,7 +669,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
@@ -701,7 +701,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 'silver' },
|
||||
@@ -735,7 +735,7 @@ suite('IndexTreeModel', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 'a', children: [{ element: 'aa' }] },
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
// console.log(`splice (${start}, ${deleteCount}, ${elements.length} [${elements.join(', ')}] )`); // debugging
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
}
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
assert.equal(model.size, 0);
|
||||
@@ -33,7 +34,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('flat', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0 },
|
||||
@@ -60,7 +61,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('nested', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
@@ -96,7 +97,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('setChildren on collapsed node', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0, collapsed: true }
|
||||
@@ -117,7 +118,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('setChildren on expanded, unrevealed node', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
@@ -143,7 +144,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('collapse state is preserved with strict identity', () => {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toSpliceable(list), { collapseByDefault: true });
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { collapseByDefault: true });
|
||||
const data = [{ element: 'father', children: [{ element: 'child' }] }];
|
||||
|
||||
model.setChildren(null, data);
|
||||
@@ -173,7 +174,7 @@ suite('ObjectTreeModel', function () {
|
||||
let compare: (a: string, b: string) => number = (a, b) => a < b ? -1 : 1;
|
||||
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const data = [
|
||||
{ element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] },
|
||||
{ element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] },
|
||||
@@ -188,7 +189,7 @@ suite('ObjectTreeModel', function () {
|
||||
let compare: (a: string, b: string) => number = () => 0;
|
||||
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const data = [
|
||||
{ element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] },
|
||||
{ element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] },
|
||||
@@ -223,7 +224,7 @@ suite('ObjectTreeModel', function () {
|
||||
|
||||
test('expandTo', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toSpliceable(list), { collapseByDefault: true });
|
||||
const model = new ObjectTreeModel<number>('test', toList(list), { collapseByDefault: true });
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
@@ -254,7 +255,7 @@ suite('ObjectTreeModel', function () {
|
||||
return fn(element) ? TreeVisibility.Visible : parentVisibility;
|
||||
}
|
||||
};
|
||||
const model = new ObjectTreeModel<string>('test', toSpliceable(list), { filter });
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { filter });
|
||||
|
||||
model.setChildren(null, [{ element: 'file', children: [{ element: 'hello' }] }]);
|
||||
assert.deepEqual(toArray(list), ['file', 'hello']);
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
<!-- Workbench Configuration -->
|
||||
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONFIGURATION}}">
|
||||
|
||||
<!-- Builtin Extensions (running out of sources) -->
|
||||
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
|
||||
|
||||
<!-- Workarounds/Hacks (remote user data uri) -->
|
||||
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
|
||||
|
||||
@@ -72,7 +75,9 @@
|
||||
'rxjs/operator/mergeAll': `${window.location.origin}/static/remote/web/node_modules/rxjs/bundles/Rx.min.js?20`,
|
||||
'rxjs/operator/filter': `${window.location.origin}/static/remote/web/node_modules/rxjs/bundles/Rx.min.js?21`,
|
||||
'sanitize-html': `${window.location.origin}/static/remote/web/node_modules/sanitize-html/dist/sanitize-html.js`,
|
||||
'ansi_up': `${window.location.origin}/static/remote/web/node_modules/ansi_up/ansi_up.js`
|
||||
'ansi_up': `${window.location.origin}/static/remote/web/node_modules/ansi_up/ansi_up.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/remote/web/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -62,7 +62,9 @@
|
||||
'rxjs/observable/fromPromise': `${window.location.origin}/static/node_modules/rxjs/bundles/Rx.min.js?6`,
|
||||
'rxjs/add/observable/fromPromise': `${window.location.origin}/static/node_modules/rxjs/bundles/Rx.min.js?7`,
|
||||
'sanitize-html': `${window.location.origin}/static/node_modules/sanitize-html/dist/sanitize-html.js`,
|
||||
'ansi_up': `${window.location.origin}/static/node_modules/ansi_up/ansi_up.js`
|
||||
'ansi_up': `${window.location.origin}/static/node_modules/ansi_up/ansi_up.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
<style>
|
||||
body {
|
||||
display: none
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body aria-label="">
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
<style>body{display: none}</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
<!-- Startup via issueReporter.js -->
|
||||
<script src="issueReporter.js"></script>
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<!-- Startup via issueReporter.js -->
|
||||
<script src="issueReporter.js"></script>
|
||||
</html>
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const bootstrapWindow = require('../../../../bootstrap-window');
|
||||
/**
|
||||
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown }}
|
||||
*/
|
||||
const bootstrapWindow = (() => {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
bootstrapWindow.load(['vs/code/electron-browser/issue/issueReporterMain'], function (issueReporter, configuration) {
|
||||
issueReporter.startup(configuration);
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
</head>
|
||||
<body aria-label="">
|
||||
<table id="process-list"></table>
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
</head>
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<body aria-label="">
|
||||
<table id="process-list"></table>
|
||||
</body>
|
||||
|
||||
<!-- Startup via processExplorer.js -->
|
||||
<script src="processExplorer.js"></script>
|
||||
|
||||
</html>
|
||||
<!-- Startup via processExplorer.js -->
|
||||
<script src="processExplorer.js"></script>
|
||||
</html>
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const bootstrapWindow = require('../../../../bootstrap-window');
|
||||
/**
|
||||
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown }}
|
||||
*/
|
||||
const bootstrapWindow = (() => {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
bootstrapWindow.load(['vs/code/electron-browser/processExplorer/processExplorerMain'], function (processExplorer, configuration) {
|
||||
processExplorer.startup(configuration.data);
|
||||
}, { forceEnableDeveloperKeybindings: true });
|
||||
}, { forceEnableDeveloperKeybindings: true });
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
Shared Process
|
||||
</body>
|
||||
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<!-- Startup via sharedProcess.js -->
|
||||
<script src="sharedProcess.js"></script>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -6,8 +6,21 @@
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const bootstrap = require('../../../../bootstrap');
|
||||
const bootstrapWindow = require('../../../../bootstrap-window');
|
||||
/**
|
||||
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options?: object) => unknown }}
|
||||
*/
|
||||
const bootstrapWindow = (() => {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @type {{ avoidMonkeyPatchFromAppInsights: () => void; }}
|
||||
*/
|
||||
const bootstrap = (() => {
|
||||
// @ts-ignore (defined in bootstrap.js)
|
||||
return window.MonacoBootstrap;
|
||||
})();
|
||||
|
||||
// Avoid Monkey Patches from Application Insights
|
||||
bootstrap.avoidMonkeyPatchFromAppInsights();
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'none'; frame-src 'self' https://*.vscode-webview-test.com; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote-resource:;">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'none'; frame-src 'self' vscode-webview: https://*.vscode-webview-test.com; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote-resource:;">
|
||||
</head>
|
||||
<body aria-label="">
|
||||
</body>
|
||||
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<!-- Startup via workbench.js -->
|
||||
<script src="workbench.js"></script>
|
||||
</html>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path="../../../../typings/require.d.ts" />
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
@@ -31,11 +33,17 @@ const perf = (function () {
|
||||
|
||||
perf.mark('renderer/started');
|
||||
|
||||
const bootstrapWindow = require('../../../../bootstrap-window');
|
||||
|
||||
// Setup shell environment
|
||||
process['lazyEnv'] = getLazyEnv();
|
||||
|
||||
/**
|
||||
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown }}
|
||||
*/
|
||||
const bootstrapWindow = (() => {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
// Load workbench main JS, CSS and NLS all in parallel. This is an
|
||||
// optimization to prevent a waterfall of loading to happen, because
|
||||
// we know for a fact that workbench.desktop.main will depend on
|
||||
@@ -55,18 +63,20 @@ bootstrapWindow.load([
|
||||
// @ts-ignore
|
||||
return require('vs/workbench/electron-browser/desktop.main').main(configuration);
|
||||
});
|
||||
}, {
|
||||
removeDeveloperKeybindingsAfterLoad: true,
|
||||
canModifyDOM: function (windowConfig) {
|
||||
showPartsSplash(windowConfig);
|
||||
},
|
||||
beforeLoaderConfig: function (windowConfig, loaderConfig) {
|
||||
loaderConfig.recordStats = true;
|
||||
},
|
||||
beforeRequire: function () {
|
||||
perf.mark('willLoadWorkbenchMain');
|
||||
{
|
||||
removeDeveloperKeybindingsAfterLoad: true,
|
||||
canModifyDOM: function (windowConfig) {
|
||||
showPartsSplash(windowConfig);
|
||||
},
|
||||
beforeLoaderConfig: function (windowConfig, loaderConfig) {
|
||||
loaderConfig.recordStats = true;
|
||||
},
|
||||
beforeRequire: function () {
|
||||
perf.mark('willLoadWorkbenchMain');
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
@@ -84,7 +94,7 @@ function showPartsSplash(configuration) {
|
||||
let data;
|
||||
if (typeof configuration.partsSplashPath === 'string') {
|
||||
try {
|
||||
data = JSON.parse(require('fs').readFileSync(configuration.partsSplashPath, 'utf8'));
|
||||
data = JSON.parse(require.__$__nodeRequire('fs').readFileSync(configuration.partsSplashPath, 'utf8'));
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
@@ -173,7 +183,7 @@ function showPartsSplash(configuration) {
|
||||
*/
|
||||
function getLazyEnv() {
|
||||
|
||||
const ipc = require('electron').ipcRenderer;
|
||||
const ipc = require.__$__nodeRequire('electron').ipcRenderer;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
const handle = setTimeout(function () {
|
||||
@@ -183,7 +193,7 @@ function getLazyEnv() {
|
||||
|
||||
ipc.once('vscode:acceptShellEnv', function (event, shellEnv) {
|
||||
clearTimeout(handle);
|
||||
bootstrapWindow.assign(process.env, shellEnv);
|
||||
Object.assign(process.env, shellEnv);
|
||||
// @ts-ignore
|
||||
resolve(process.env);
|
||||
});
|
||||
|
||||
@@ -80,6 +80,8 @@ import { INativeEnvironmentService } from 'vs/platform/environment/node/environm
|
||||
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService';
|
||||
import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService';
|
||||
import { createServer, AddressInfo } from 'net';
|
||||
import { IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
|
||||
export class CodeApplication extends Disposable {
|
||||
private windowsMainService: IWindowsMainService | undefined;
|
||||
@@ -132,7 +134,11 @@ export class CodeApplication extends Disposable {
|
||||
//
|
||||
// !!! DO NOT CHANGE without consulting the documentation !!!
|
||||
//
|
||||
// app.on('remote-get-guest-web-contents', event => event.preventDefault()); // TODO@Matt revisit this need for <webview>
|
||||
app.on('remote-get-guest-web-contents', event => {
|
||||
this.logService.trace('App#on(remote-get-guest-web-contents): prevented');
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
app.on('remote-require', (event, sender, module) => {
|
||||
this.logService.trace('App#on(remote-require): prevented');
|
||||
|
||||
@@ -172,11 +178,12 @@ export class CodeApplication extends Disposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%20role%3D%22document%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E') {
|
||||
return true;
|
||||
const uri = URI.parse(source);
|
||||
if (uri.scheme === Schemas.vscodeWebview) {
|
||||
return uri.path === '/index.html' || uri.path === '/electron-browser/index.html';
|
||||
}
|
||||
|
||||
const srcUri = URI.parse(source).fsPath.toLowerCase();
|
||||
const srcUri = uri.fsPath.toLowerCase();
|
||||
const rootUri = URI.file(this.environmentService.appRoot).fsPath.toLowerCase();
|
||||
|
||||
return srcUri.startsWith(rootUri + sep);
|
||||
@@ -831,20 +838,93 @@ class ElectronExtensionHostDebugBroadcastChannel<TContext> extends ExtensionHost
|
||||
super();
|
||||
}
|
||||
|
||||
async call(ctx: TContext, command: string, arg?: any): Promise<any> {
|
||||
call(ctx: TContext, command: string, arg?: any): Promise<any> {
|
||||
if (command === 'openExtensionDevelopmentHostWindow') {
|
||||
const env = arg[1];
|
||||
const pargs = parseArgs(arg[0], OPTIONS);
|
||||
const extDevPaths = pargs.extensionDevelopmentPath;
|
||||
if (extDevPaths) {
|
||||
this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
|
||||
context: OpenContext.API,
|
||||
cli: pargs,
|
||||
userEnv: Object.keys(env).length > 0 ? env : undefined
|
||||
});
|
||||
}
|
||||
return this.openExtensionDevelopmentHostWindow(arg[0], arg[1], arg[2]);
|
||||
} else {
|
||||
return super.call(ctx, command, arg);
|
||||
}
|
||||
}
|
||||
|
||||
private async openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise<IOpenExtensionWindowResult> {
|
||||
const pargs = parseArgs(args, OPTIONS);
|
||||
const extDevPaths = pargs.extensionDevelopmentPath;
|
||||
if (!extDevPaths) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const [codeWindow] = this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
|
||||
context: OpenContext.API,
|
||||
cli: pargs,
|
||||
userEnv: Object.keys(env).length > 0 ? env : undefined
|
||||
});
|
||||
|
||||
if (!debugRenderer) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const debug = codeWindow.win.webContents.debugger;
|
||||
|
||||
let listeners = debug.isAttached() ? Infinity : 0;
|
||||
const server = createServer(listener => {
|
||||
if (listeners++ === 0) {
|
||||
debug.attach();
|
||||
}
|
||||
|
||||
let closed = false;
|
||||
const writeMessage = (message: object) => {
|
||||
if (!closed) { // in case sendCommand promises settle after closed
|
||||
listener.write(JSON.stringify(message) + '\0'); // null-delimited, CDP-compatible
|
||||
}
|
||||
};
|
||||
|
||||
const onMessage = (_event: Event, method: string, params: unknown, sessionId?: string) =>
|
||||
writeMessage(({ method, params, sessionId }));
|
||||
|
||||
codeWindow.win.on('close', () => {
|
||||
debug.removeListener('message', onMessage);
|
||||
listener.end();
|
||||
closed = true;
|
||||
});
|
||||
|
||||
debug.addListener('message', onMessage);
|
||||
|
||||
let buf = Buffer.alloc(0);
|
||||
listener.on('data', data => {
|
||||
buf = Buffer.concat([buf, data]);
|
||||
for (let delimiter = buf.indexOf(0); delimiter !== -1; delimiter = buf.indexOf(0)) {
|
||||
let data: { id: number; sessionId: string; params: {} };
|
||||
try {
|
||||
const contents = buf.slice(0, delimiter).toString('utf8');
|
||||
buf = buf.slice(delimiter + 1);
|
||||
data = JSON.parse(contents);
|
||||
} catch (e) {
|
||||
console.error('error reading cdp line', e);
|
||||
}
|
||||
|
||||
// depends on a new API for which electron.d.ts has not been updated:
|
||||
// @ts-ignore
|
||||
debug.sendCommand(data.method, data.params, data.sessionId)
|
||||
.then((result: object) => writeMessage({ id: data.id, sessionId: data.sessionId, result }))
|
||||
.catch((error: Error) => writeMessage({ id: data.id, sessionId: data.sessionId, error: { code: 0, message: error.message } }));
|
||||
}
|
||||
});
|
||||
|
||||
listener.on('error', err => {
|
||||
console.error('error on cdp pipe:', err);
|
||||
});
|
||||
|
||||
listener.on('close', () => {
|
||||
closed = true;
|
||||
if (--listeners === 0) {
|
||||
debug.detach();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise(r => server.listen(0, r));
|
||||
codeWindow.win.on('close', () => server.close());
|
||||
|
||||
return { rendererDebugPort: (server.address() as AddressInfo).port };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ export class ProxyAuthHandler extends Disposable {
|
||||
title: 'VS Code',
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
webviewTag: true,
|
||||
enableWebSQL: false,
|
||||
enableRemoteModule: false,
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,6 +47,7 @@ export class SharedProcess implements ISharedProcess {
|
||||
nodeIntegration: true,
|
||||
webgl: false,
|
||||
enableWebSQL: false,
|
||||
enableRemoteModule: false,
|
||||
nativeWindowOpen: true,
|
||||
disableBlinkFeatures: 'Auxclick' // do NOT change, allows us to identify this window as shared-process in the process explorer
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifec
|
||||
import { IStorageMainService } from 'vs/platform/storage/node/storageMainService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
const RUN_TEXTMATE_IN_WORKER = false;
|
||||
|
||||
export interface IWindowCreationOptions {
|
||||
state: IWindowState;
|
||||
extensionDevelopmentPath?: string[];
|
||||
@@ -168,9 +166,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
webPreferences: {
|
||||
preload: URI.parse(this.doGetPreloadUrl()).fsPath,
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: RUN_TEXTMATE_IN_WORKER,
|
||||
webviewTag: true,
|
||||
enableWebSQL: false,
|
||||
enableRemoteModule: false,
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
};
|
||||
@@ -809,7 +807,14 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// fullscreen gets special treatment
|
||||
if (this.isFullScreen) {
|
||||
const display = screen.getDisplayMatching(this.getBounds());
|
||||
let display: Display | undefined;
|
||||
try {
|
||||
display = screen.getDisplayMatching(this.getBounds());
|
||||
} catch (error) {
|
||||
// Electron has weird conditions under which it throws errors
|
||||
// e.g. https://github.com/microsoft/vscode/issues/100334 when
|
||||
// large numbers are passed in
|
||||
}
|
||||
|
||||
const defaultState = defaultWindowState();
|
||||
|
||||
@@ -976,8 +981,17 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
// Multi Monitor (non-fullscreen): ensure window is within display bounds
|
||||
const display = screen.getDisplayMatching({ x: state.x, y: state.y, width: state.width, height: state.height });
|
||||
const displayWorkingArea = this.getWorkingArea(display);
|
||||
let display: Display | undefined;
|
||||
let displayWorkingArea: Rectangle | undefined;
|
||||
try {
|
||||
display = screen.getDisplayMatching({ x: state.x, y: state.y, width: state.width, height: state.height });
|
||||
displayWorkingArea = this.getWorkingArea(display);
|
||||
} catch (error) {
|
||||
// Electron has weird conditions under which it throws errors
|
||||
// e.g. https://github.com/microsoft/vscode/issues/100334 when
|
||||
// large numbers are passed in
|
||||
}
|
||||
|
||||
if (
|
||||
display && // we have a display matching the desired bounds
|
||||
displayWorkingArea && // we have valid working area bounds
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function main(argv: string[]): Promise<any> {
|
||||
|
||||
// Help
|
||||
if (args.help) {
|
||||
const executable = `${product.applicationName}${os.platform() === 'win32' ? '.exe' : ''}`;
|
||||
const executable = `${product.applicationName}${isWindows ? '.exe' : ''}`;
|
||||
console.log(buildHelpMessage(product.nameLong, executable, product.version, OPTIONS));
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { areSameExtensions, adoptToGalleryExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
|
||||
import { IExtensionManifest, ExtensionType, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionType, isLanguagePackExtension, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -102,8 +102,7 @@ export class Main {
|
||||
|
||||
private async listExtensions(showVersions: boolean, category?: string): Promise<void> {
|
||||
let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
// TODO: we should save this array in a common place so that the command and extensionQuery can use it that way changing it is easier
|
||||
const categories = ['"programming languages"', 'snippets', 'linters', 'themes', 'debuggers', 'formatters', 'keymaps', '"scm providers"', 'other', '"extension packs"', '"language packs"'];
|
||||
const categories = EXTENSION_CATEGORIES.map(c => c.toLowerCase());
|
||||
if (category && category !== '') {
|
||||
if (categories.indexOf(category.toLowerCase()) < 0) {
|
||||
console.log('Invalid category please enter a valid category. To list valid categories run --category without a category specified');
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Command, EditorCommand, ICommandOptions, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection';
|
||||
import { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from 'vs/editor/common/controller/cursorCommon';
|
||||
@@ -20,7 +20,6 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { Handler, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -276,6 +275,48 @@ export namespace RevealLine_ {
|
||||
};
|
||||
}
|
||||
|
||||
abstract class EditorOrNativeTextInputCommand {
|
||||
|
||||
constructor(target: MultiCommand) {
|
||||
// 1. handle case when focus is in editor.
|
||||
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
this.runEditorCommand(accessor, focusedEditor, args);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 2. handle case when focus is in some other `input` / `textarea`.
|
||||
target.addImplementation(1000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if focused on an element that allows for entering text
|
||||
const activeElement = <HTMLElement>document.activeElement;
|
||||
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
||||
this.runDOMCommand();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 3. (default) handle case when focus is somewhere else.
|
||||
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
// Redirecting to active editor
|
||||
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
||||
if (activeEditor) {
|
||||
activeEditor.focus();
|
||||
this.runEditorCommand(accessor, activeEditor, args);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public abstract runDOMCommand(): void;
|
||||
public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void;
|
||||
}
|
||||
|
||||
export namespace CoreNavigationCommands {
|
||||
|
||||
class BaseMoveToCommand extends CoreEditorCommand {
|
||||
@@ -1594,25 +1635,32 @@ export namespace CoreNavigationCommands {
|
||||
}
|
||||
});
|
||||
|
||||
export const SelectAll: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
|
||||
export const SelectAll = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'selectAll',
|
||||
precondition: undefined
|
||||
});
|
||||
super(SelectAllCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
const viewModel = editor._getViewModel();
|
||||
if (!viewModel) {
|
||||
// the editor has no view => has no cursors
|
||||
return;
|
||||
}
|
||||
this.runCoreEditorCommand(viewModel, args);
|
||||
}
|
||||
|
||||
public runCoreEditorCommand(viewModel: IViewModel, args: any): void {
|
||||
viewModel.model.pushStackElement();
|
||||
viewModel.setCursorStates(
|
||||
args.source,
|
||||
'keyboard',
|
||||
CursorChangeReason.Explicit,
|
||||
[
|
||||
CursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
}();
|
||||
|
||||
export const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
|
||||
constructor() {
|
||||
@@ -1655,97 +1703,6 @@ registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyM
|
||||
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);
|
||||
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);
|
||||
|
||||
/**
|
||||
* A command that will:
|
||||
* 1. invoke a command on the focused editor.
|
||||
* 2. otherwise, invoke a browser built-in command on the `activeElement`.
|
||||
* 3. otherwise, invoke a command on the workbench active editor.
|
||||
*/
|
||||
abstract class EditorOrNativeTextInputCommand extends Command {
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
return this.runEditorCommand(accessor, focusedEditor, args);
|
||||
}
|
||||
|
||||
// Ignore this action when user is focused on an element that allows for entering text
|
||||
const activeElement = <HTMLElement>document.activeElement;
|
||||
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
||||
return this.runDOMCommand();
|
||||
}
|
||||
|
||||
// Redirecting to active editor
|
||||
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
||||
if (activeEditor) {
|
||||
activeEditor.focus();
|
||||
return this.runEditorCommand(accessor, activeEditor, args);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract runDOMCommand(): void;
|
||||
public abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void;
|
||||
}
|
||||
|
||||
class SelectAllCommand extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.selectAll',
|
||||
precondition: EditorContextKeys.textInputFocus,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: null,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('selectAll', "Select All"),
|
||||
order: 1
|
||||
}]
|
||||
});
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
args = args || {};
|
||||
args.source = 'keyboard';
|
||||
CoreNavigationCommands.SelectAll.runEditorCommand(accessor, editor, args);
|
||||
}
|
||||
}
|
||||
|
||||
class UndoCommand extends EditorOrNativeTextInputCommand {
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('undo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().undo();
|
||||
}
|
||||
}
|
||||
|
||||
class RedoCommand extends EditorOrNativeTextInputCommand {
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('redo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().redo();
|
||||
}
|
||||
}
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
@@ -1881,53 +1838,35 @@ export namespace CoreEditingCommands {
|
||||
}
|
||||
});
|
||||
|
||||
export const Undo: UndoCommand = registerCommand(new UndoCommand({
|
||||
id: 'undo',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('undo', "Undo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
export const Undo = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super(UndoCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('undo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().undo();
|
||||
}
|
||||
}();
|
||||
|
||||
export const DefaultUndo: UndoCommand = registerCommand(new UndoCommand({ id: 'default:undo', precondition: EditorContextKeys.writable }));
|
||||
|
||||
export const Redo: RedoCommand = registerCommand(new RedoCommand({
|
||||
id: 'redo',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('redo', "Redo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
export const DefaultRedo: RedoCommand = registerCommand(new RedoCommand({ id: 'default:redo', precondition: EditorContextKeys.writable }));
|
||||
export const Redo = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super(RedoCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('redo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().redo();
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1956,8 +1895,6 @@ class EditorHandlerCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
registerCommand(new SelectAllCommand());
|
||||
|
||||
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
|
||||
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
|
||||
registerCommand(new EditorHandlerCommand(handlerId, handlerId, description));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -17,11 +18,13 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { withNullAsUndefined, assertType } from 'vs/base/common/types';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
|
||||
export type ServicesAccessor = InstantiationServicesAccessor;
|
||||
@@ -139,6 +142,66 @@ export abstract class Command {
|
||||
|
||||
//#endregion Command
|
||||
|
||||
//#region MultiplexingCommand
|
||||
|
||||
/**
|
||||
* Potential override for a command.
|
||||
*
|
||||
* @return `true` if the command was successfully run. This stops other overrides from being executed.
|
||||
*/
|
||||
export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean;
|
||||
|
||||
export class MultiCommand extends Command {
|
||||
|
||||
private readonly _implementations: [number, CommandImplementation][] = [];
|
||||
|
||||
/**
|
||||
* A higher priority gets to be looked at first
|
||||
*/
|
||||
public addImplementation(priority: number, implementation: CommandImplementation): IDisposable {
|
||||
this._implementations.push([priority, implementation]);
|
||||
this._implementations.sort((a, b) => b[0] - a[0]);
|
||||
return {
|
||||
dispose: () => {
|
||||
for (let i = 0; i < this._implementations.length; i++) {
|
||||
if (this._implementations[i][1] === implementation) {
|
||||
this._implementations.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
||||
for (const impl of this._implementations) {
|
||||
if (impl[1](accessor, args)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* A command that delegates to another command's implementation.
|
||||
*
|
||||
* This lets different commands be registered but share the same implementation
|
||||
*/
|
||||
export class ProxyCommand extends Command {
|
||||
constructor(
|
||||
private readonly command: Command,
|
||||
opts: ICommandOptions
|
||||
) {
|
||||
super(opts);
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
||||
return this.command.runCommand(accessor, args);
|
||||
}
|
||||
}
|
||||
|
||||
//#region EditorCommand
|
||||
|
||||
export interface IContributionCommandOptions<T> extends ICommandOptions {
|
||||
@@ -379,8 +442,10 @@ export function registerEditorCommand<T extends EditorCommand>(editorCommand: T)
|
||||
return editorCommand;
|
||||
}
|
||||
|
||||
export function registerEditorAction(ctor: { new(): EditorAction; }): void {
|
||||
EditorContributionRegistry.INSTANCE.registerEditorAction(new ctor());
|
||||
export function registerEditorAction<T extends EditorAction>(ctor: { new(): T; }): T {
|
||||
const action = new ctor();
|
||||
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
export function registerInstantiatedEditorAction(editorAction: EditorAction): void {
|
||||
@@ -475,3 +540,75 @@ class EditorContributionRegistry {
|
||||
|
||||
}
|
||||
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
}
|
||||
|
||||
export const UndoCommand = registerCommand(new MultiCommand({
|
||||
id: 'undo',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('undo', "Undo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
registerCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));
|
||||
|
||||
export const RedoCommand = registerCommand(new MultiCommand({
|
||||
id: 'redo',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('redo', "Redo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
registerCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));
|
||||
|
||||
export const SelectAllCommand = registerCommand(new MultiCommand({
|
||||
id: 'editor.action.selectAll',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
kbExpr: null,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('selectAll', "Select All"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { CoreEditorCommand, CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -35,8 +35,6 @@ export interface IMouseDispatchData {
|
||||
}
|
||||
|
||||
export interface ICommandDelegate {
|
||||
executeEditorCommand(editorCommand: CoreEditorCommand, args: any): void;
|
||||
|
||||
paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;
|
||||
type(text: string): void;
|
||||
replacePreviousChar(text: string, replaceCharCnt: number): void;
|
||||
@@ -64,11 +62,6 @@ export class ViewController {
|
||||
this.commandDelegate = commandDelegate;
|
||||
}
|
||||
|
||||
private _execMouseCommand(editorCommand: CoreEditorCommand, args: any): void {
|
||||
args.source = 'mouse';
|
||||
this.commandDelegate.executeEditorCommand(editorCommand, args);
|
||||
}
|
||||
|
||||
public paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {
|
||||
this.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);
|
||||
}
|
||||
@@ -94,7 +87,7 @@ export class ViewController {
|
||||
}
|
||||
|
||||
public setSelection(modelSelection: Selection): void {
|
||||
this.commandDelegate.executeEditorCommand(CoreNavigationCommands.SetSelection, {
|
||||
CoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'keyboard',
|
||||
selection: modelSelection
|
||||
});
|
||||
@@ -214,22 +207,24 @@ export class ViewController {
|
||||
private _usualArgs(viewPosition: Position) {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
return {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition
|
||||
};
|
||||
}
|
||||
|
||||
public moveTo(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.MoveTo, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _moveToSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
this._execMouseCommand(CoreNavigationCommands.ColumnSelect, {
|
||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition,
|
||||
mouseColumn: mouseColumn,
|
||||
@@ -239,7 +234,8 @@ export class ViewController {
|
||||
|
||||
private _createCursor(viewPosition: Position, wholeLine: boolean): void {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
this._execMouseCommand(CoreNavigationCommands.CreateCursor, {
|
||||
CoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition,
|
||||
wholeLine: wholeLine
|
||||
@@ -247,39 +243,39 @@ export class ViewController {
|
||||
}
|
||||
|
||||
private _lastCursorMoveToSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorMoveToSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _wordSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.WordSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _wordSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.WordSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorWordSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorWordSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lineSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LineSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lineSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LineSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorLineSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorLineSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _selectAll(): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.SelectAll, {});
|
||||
CoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
|
||||
@@ -15,7 +15,6 @@ import { hash } from 'vs/base/common/hash';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
@@ -1552,9 +1551,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
let commandDelegate: ICommandDelegate;
|
||||
if (this.isSimpleWidget) {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(viewModel, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
this._paste('keyboard', text, pasteOnNewLine, multicursorText, mode);
|
||||
},
|
||||
@@ -1576,9 +1572,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
};
|
||||
} else {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(viewModel, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
const payload: editorCommon.PastePayload = { text, pasteOnNewLine, multicursorText, mode };
|
||||
this._commandService.executeCommand(editorCommon.Handler.Paste, payload);
|
||||
@@ -2018,5 +2011,5 @@ registerThemingParticipant((theme, collector) => {
|
||||
}
|
||||
|
||||
const deprecatedForeground = theme.getColor(editorForeground) || 'inherit';
|
||||
collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`);
|
||||
collector.addRule(`.monaco-editor.showDeprecated .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`);
|
||||
});
|
||||
|
||||
@@ -503,8 +503,13 @@ const editorConfiguration: IConfigurationNode = {
|
||||
description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.")
|
||||
},
|
||||
'editor.semanticHighlighting.enabled': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
enum: [true, false, 'configuredByTheme'],
|
||||
enumDescriptions: [
|
||||
nls.localize('semanticHighlighting.true', 'Semantic highlighting enabled for all color themes.'),
|
||||
nls.localize('semanticHighlighting.false', 'Semantic highlighting disabled for all color themes.'),
|
||||
nls.localize('semanticHighlighting.configuredByTheme', 'Semantic highlighting is configured by the current color theme\'s `semanticHighlighting` setting.')
|
||||
],
|
||||
default: 'configuredByTheme',
|
||||
description: nls.localize('semanticHighlighting.enabled', "Controls whether the semanticHighlighting is shown for the languages that support it.")
|
||||
},
|
||||
'editor.stablePeek': {
|
||||
|
||||
@@ -594,6 +594,10 @@ export interface IEditorOptions {
|
||||
* Defaults to false.
|
||||
*/
|
||||
definitionLinkOpensInPeek?: boolean;
|
||||
/**
|
||||
* Controls strikethrough deprecated variables.
|
||||
*/
|
||||
showDeprecated?: boolean;
|
||||
}
|
||||
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
@@ -1219,22 +1223,28 @@ class EditorClassName extends ComputedEditorOption<EditorOption.editorClassName,
|
||||
}
|
||||
|
||||
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {
|
||||
let className = 'monaco-editor';
|
||||
const classNames = ['monaco-editor'];
|
||||
if (options.get(EditorOption.extraEditorClassName)) {
|
||||
className += ' ' + options.get(EditorOption.extraEditorClassName);
|
||||
classNames.push(options.get(EditorOption.extraEditorClassName));
|
||||
}
|
||||
if (env.extraEditorClassName) {
|
||||
className += ' ' + env.extraEditorClassName;
|
||||
classNames.push(env.extraEditorClassName);
|
||||
}
|
||||
if (options.get(EditorOption.mouseStyle) === 'default') {
|
||||
className += ' mouse-default';
|
||||
classNames.push('mouse-default');
|
||||
} else if (options.get(EditorOption.mouseStyle) === 'copy') {
|
||||
className += ' mouse-copy';
|
||||
classNames.push('mouse-copy');
|
||||
}
|
||||
|
||||
if (options.get(EditorOption.showUnused)) {
|
||||
className += ' showUnused';
|
||||
classNames.push('showUnused');
|
||||
}
|
||||
return className;
|
||||
|
||||
if (options.get(EditorOption.showDeprecated)) {
|
||||
classNames.push('showDeprecated');
|
||||
}
|
||||
|
||||
return classNames.join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3599,6 +3609,7 @@ export const enum EditorOption {
|
||||
wordWrapMinified,
|
||||
wrappingIndent,
|
||||
wrappingStrategy,
|
||||
showDeprecated,
|
||||
|
||||
// Leave these at the end (because they have dependencies!)
|
||||
editorClassName,
|
||||
@@ -4085,6 +4096,10 @@ export const EditorOptions = {
|
||||
EditorOption.showUnused, 'showUnused', true,
|
||||
{ description: nls.localize('showUnused', "Controls fading out of unused code.") }
|
||||
)),
|
||||
showDeprecated: register(new EditorBooleanOption(
|
||||
EditorOption.showDeprecated, 'showDeprecated', true,
|
||||
{ description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") }
|
||||
)),
|
||||
snippetSuggestions: register(new EditorStringEnumOption(
|
||||
EditorOption.snippetSuggestions, 'snippetSuggestions',
|
||||
'inline' as 'top' | 'bottom' | 'inline' | 'none',
|
||||
|
||||
@@ -163,11 +163,9 @@ export class WordOperations {
|
||||
public static moveWordLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {
|
||||
let lineNumber = position.lineNumber;
|
||||
let column = position.column;
|
||||
let movedToPreviousLine = false;
|
||||
|
||||
if (column === 1) {
|
||||
if (lineNumber > 1) {
|
||||
movedToPreviousLine = true;
|
||||
lineNumber = lineNumber - 1;
|
||||
column = model.getLineMaxColumn(lineNumber);
|
||||
}
|
||||
@@ -176,17 +174,6 @@ export class WordOperations {
|
||||
let prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, column));
|
||||
|
||||
if (wordNavigationType === WordNavigationType.WordStart) {
|
||||
|
||||
if (prevWordOnLine && !movedToPreviousLine) {
|
||||
// Special case for Visual Studio compatibility:
|
||||
// when starting in the trim whitespace at the end of a line,
|
||||
// go to the end of the last word
|
||||
const lastWhitespaceColumn = model.getLineLastNonWhitespaceColumn(lineNumber);
|
||||
if (lastWhitespaceColumn < column) {
|
||||
return new Position(lineNumber, prevWordOnLine.end + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ export class InternalEditorAction implements IEditorAction {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const r = this._run();
|
||||
return r ? r : Promise.resolve(undefined);
|
||||
return this._run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
|
||||
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { TextChange } from 'vs/editor/common/model/textChange';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
|
||||
@@ -278,6 +278,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
* Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
|
||||
*/
|
||||
private _alternativeVersionId: number;
|
||||
private _initialUndoRedoSnapshot: ResourceEditStackSnapshot | null;
|
||||
private readonly _isTooLargeForSyncing: boolean;
|
||||
private readonly _isTooLargeForTokenization: boolean;
|
||||
|
||||
@@ -351,6 +352,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
|
||||
this._versionId = 1;
|
||||
this._alternativeVersionId = 1;
|
||||
this._initialUndoRedoSnapshot = null;
|
||||
|
||||
this._isDisposed = false;
|
||||
this._isDisposing = false;
|
||||
@@ -719,6 +721,11 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
return this._alternativeVersionId;
|
||||
}
|
||||
|
||||
public getInitialUndoRedoSnapshot(): ResourceEditStackSnapshot | null {
|
||||
this._assertNotDisposed();
|
||||
return this._initialUndoRedoSnapshot;
|
||||
}
|
||||
|
||||
public getOffsetAt(rawPosition: IPosition): number {
|
||||
this._assertNotDisposed();
|
||||
let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, StringOffsetValidationType.Relaxed);
|
||||
@@ -744,6 +751,10 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
this._alternativeVersionId = newAlternativeVersionId;
|
||||
}
|
||||
|
||||
public _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot: ResourceEditStackSnapshot | null): void {
|
||||
this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
|
||||
}
|
||||
|
||||
public getValue(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): string {
|
||||
this._assertNotDisposed();
|
||||
const fullModelRange = this.getFullModelRange();
|
||||
@@ -1187,6 +1198,9 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
try {
|
||||
this._onDidChangeDecorations.beginDeferredEmit();
|
||||
this._eventEmitter.beginDeferredEmit();
|
||||
if (this._initialUndoRedoSnapshot === null) {
|
||||
this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
|
||||
}
|
||||
this._commandManager.pushEOL(eol);
|
||||
} finally {
|
||||
this._eventEmitter.endDeferredEmit();
|
||||
@@ -1311,6 +1325,9 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
|
||||
this._trimAutoWhitespaceLines = null;
|
||||
}
|
||||
if (this._initialUndoRedoSnapshot === null) {
|
||||
this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
|
||||
}
|
||||
return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
|
||||
}
|
||||
|
||||
|
||||
@@ -548,8 +548,12 @@ export class Searcher {
|
||||
if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) {
|
||||
if (matchLength === 0) {
|
||||
// the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here
|
||||
// we attempt to recover from that by advancing by one
|
||||
this._searchRegex.lastIndex += 1;
|
||||
// we attempt to recover from that by advancing by two if surrogate pair found and by one otherwise
|
||||
if (strings.getNextCodePoint(text, textLength, this._searchRegex.lastIndex) > 0xFFFF) {
|
||||
this._searchRegex.lastIndex += 2;
|
||||
} else {
|
||||
this._searchRegex.lastIndex += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Exit early if the regex matches the same range twice
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { IRelativePattern, match as matchGlobPattern } from 'vs/base/common/glob';
|
||||
import { URI } from 'vs/base/common/uri'; // TODO@Alex
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
|
||||
export interface LanguageFilter {
|
||||
language?: string;
|
||||
@@ -83,7 +84,19 @@ export function score(selector: LanguageSelector | undefined, candidateUri: URI,
|
||||
}
|
||||
|
||||
if (pattern) {
|
||||
if (pattern === candidateUri.fsPath || matchGlobPattern(pattern, candidateUri.fsPath)) {
|
||||
let normalizedPattern: string | IRelativePattern;
|
||||
if (typeof pattern === 'string') {
|
||||
normalizedPattern = pattern;
|
||||
} else {
|
||||
// Since this pattern has a `base` property, we need
|
||||
// to normalize this path first before passing it on
|
||||
// because we will compare it against `Uri.fsPath`
|
||||
// which uses platform specific separators.
|
||||
// Refs: https://github.com/microsoft/vscode/issues/99938
|
||||
normalizedPattern = { ...pattern, base: normalize(pattern.base) };
|
||||
}
|
||||
|
||||
if (normalizedPattern === candidateUri.fsPath || matchGlobPattern(normalizedPattern, candidateUri.fsPath)) {
|
||||
ret = 10;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
@@ -154,7 +154,7 @@ function getClassifier(): CharacterClassifier<CharacterClass> {
|
||||
if (_classifier === null) {
|
||||
_classifier = new CharacterClassifier<CharacterClass>(CharacterClass.None);
|
||||
|
||||
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
|
||||
const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';
|
||||
for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {
|
||||
_classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { regExpFlags } from 'vs/base/common/strings';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
|
||||
/**
|
||||
* Stop syncing a model to the worker if it was not needed for 1 min.
|
||||
@@ -380,6 +381,7 @@ export class EditorWorkerClient extends Disposable {
|
||||
private _worker: IWorkerClient<EditorSimpleWorker> | null;
|
||||
private readonly _workerFactory: DefaultWorkerFactory;
|
||||
private _modelManager: EditorModelManager | null;
|
||||
private _disposed = false;
|
||||
|
||||
constructor(modelService: IModelService, keepIdleModels: boolean, label: string | undefined) {
|
||||
super();
|
||||
@@ -427,6 +429,9 @@ export class EditorWorkerClient extends Disposable {
|
||||
}
|
||||
|
||||
protected _withSyncedResources(resources: URI[]): Promise<EditorSimpleWorker> {
|
||||
if (this._disposed) {
|
||||
return Promise.reject(canceled());
|
||||
}
|
||||
return this._getProxy().then((proxy) => {
|
||||
this._getOrCreateModelManager(proxy).ensureSyncedResources(resources);
|
||||
return proxy;
|
||||
@@ -495,4 +500,9 @@ export class EditorWorkerClient extends Disposable {
|
||||
return proxy.navigateValueSet(resource.toString(), range, up, wordDef, wordDefFlags);
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this._disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { StringSHA1 } from 'vs/base/common/hash';
|
||||
import { SingleModelEditStackElement, MultiModelEditStackElement, EditStackElement, isEditStackElement } from 'vs/editor/common/model/editStack';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
|
||||
|
||||
export interface IEditorSemanticHighlightingOptions {
|
||||
enabled?: boolean;
|
||||
enabled: true | false | 'configuredByTheme';
|
||||
}
|
||||
|
||||
function MODEL_ID(resource: URI): string {
|
||||
@@ -51,7 +51,7 @@ function computeModelSha1(model: ITextModel): string {
|
||||
|
||||
|
||||
class ModelData implements IDisposable {
|
||||
public readonly model: ITextModel;
|
||||
public readonly model: TextModel;
|
||||
|
||||
private _languageSelection: ILanguageSelection | null;
|
||||
private _languageSelectionListener: IDisposable | null;
|
||||
@@ -59,7 +59,7 @@ class ModelData implements IDisposable {
|
||||
private readonly _modelEventListeners = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
model: ITextModel,
|
||||
model: TextModel,
|
||||
onWillDispose: (model: ITextModel) => void,
|
||||
onDidChangeLanguage: (model: ITextModel, e: IModelLanguageChangedEvent) => void
|
||||
) {
|
||||
@@ -138,6 +138,7 @@ function isEditStackElements(elements: IUndoRedoElement[]): elements is EditStac
|
||||
class DisposedModelInfo {
|
||||
constructor(
|
||||
public readonly uri: URI,
|
||||
public readonly initialUndoRedoSnapshot: ResourceEditStackSnapshot | null,
|
||||
public readonly time: number,
|
||||
public readonly sharesUndoRedoStack: boolean,
|
||||
public readonly heapSize: number,
|
||||
@@ -362,7 +363,9 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
|
||||
const disposedModel = disposedModels.shift()!;
|
||||
this._removeDisposedModel(disposedModel.uri);
|
||||
this._undoRedoService.removeElements(disposedModel.uri);
|
||||
if (disposedModel.initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(disposedModel.initialUndoRedoSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,9 +393,12 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
if (sha1IsEqual) {
|
||||
model._overwriteVersionId(disposedModelData.versionId);
|
||||
model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
|
||||
model._overwriteInitialUndoRedoSnapshot(disposedModelData.initialUndoRedoSnapshot);
|
||||
}
|
||||
} else {
|
||||
this._undoRedoService.removeElements(resource);
|
||||
if (disposedModelData.initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(disposedModelData.initialUndoRedoSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
const modelId = MODEL_ID(model.uri);
|
||||
@@ -541,7 +547,10 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
|
||||
if (!maintainUndoRedoStack) {
|
||||
if (!sharesUndoRedoStack) {
|
||||
this._undoRedoService.removeElements(resource);
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
}
|
||||
modelData.model.dispose();
|
||||
return;
|
||||
@@ -550,7 +559,10 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
|
||||
if (!sharesUndoRedoStack && heapSize > maxMemory) {
|
||||
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
|
||||
this._undoRedoService.removeElements(resource);
|
||||
const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
|
||||
if (initialUndoRedoSnapshot !== null) {
|
||||
this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
|
||||
}
|
||||
modelData.model.dispose();
|
||||
return;
|
||||
}
|
||||
@@ -559,7 +571,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
|
||||
// We only invalidate the elements, but they remain in the undo-redo service.
|
||||
this._undoRedoService.setElementsValidFlag(resource, false, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
|
||||
this._insertDisposedModel(new DisposedModelInfo(resource, Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
|
||||
this._insertDisposedModel(new DisposedModelInfo(resource, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
|
||||
|
||||
modelData.model.dispose();
|
||||
}
|
||||
@@ -621,11 +633,11 @@ export interface ILineSequence {
|
||||
export const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';
|
||||
|
||||
export function isSemanticColoringEnabled(model: ITextModel, themeService: IThemeService, configurationService: IConfigurationService): boolean {
|
||||
if (!themeService.getColorTheme().semanticHighlighting) {
|
||||
return false;
|
||||
const setting = configurationService.getValue<IEditorSemanticHighlightingOptions>(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri })?.enabled;
|
||||
if (typeof setting === 'boolean') {
|
||||
return setting;
|
||||
}
|
||||
const options = configurationService.getValue<IEditorSemanticHighlightingOptions>(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri });
|
||||
return Boolean(options && options.enabled);
|
||||
return themeService.getColorTheme().semanticHighlighting;
|
||||
}
|
||||
|
||||
class SemanticColoringFeature extends Disposable {
|
||||
|
||||
@@ -279,11 +279,12 @@ export enum EditorOption {
|
||||
wordWrapMinified = 109,
|
||||
wrappingIndent = 110,
|
||||
wrappingStrategy = 111,
|
||||
editorClassName = 112,
|
||||
pixelRatio = 113,
|
||||
tabFocusMode = 114,
|
||||
layoutInfo = 115,
|
||||
wrappingInfo = 116
|
||||
showDeprecated = 112,
|
||||
editorClassName = 113,
|
||||
pixelRatio = 114,
|
||||
tabFocusMode = 115,
|
||||
layoutInfo = 116,
|
||||
wrappingInfo = 117
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -210,12 +210,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
const width = layoutInfo.contentWidth;
|
||||
const height = layoutInfo.height;
|
||||
const scrollDimensions = this._scrollable.getScrollDimensions();
|
||||
const scrollWidth = scrollDimensions.scrollWidth;
|
||||
const contentWidth = scrollDimensions.contentWidth;
|
||||
this._scrollable.setScrollDimensions(new EditorScrollDimensions(
|
||||
width,
|
||||
scrollDimensions.contentWidth,
|
||||
height,
|
||||
this._getContentHeight(width, height, scrollWidth)
|
||||
this._getContentHeight(width, height, contentWidth)
|
||||
));
|
||||
} else {
|
||||
this._updateHeight();
|
||||
@@ -250,14 +250,14 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
return scrollbar.horizontalScrollbarSize;
|
||||
}
|
||||
|
||||
private _getContentHeight(width: number, height: number, scrollWidth: number): number {
|
||||
private _getContentHeight(width: number, height: number, contentWidth: number): number {
|
||||
const options = this._configuration.options;
|
||||
|
||||
let result = this._linesLayout.getLinesTotalHeight();
|
||||
if (options.get(EditorOption.scrollBeyondLastLine)) {
|
||||
result += height - options.get(EditorOption.lineHeight);
|
||||
} else {
|
||||
result += this._getHorizontalScrollbarHeight(width, scrollWidth);
|
||||
result += this._getHorizontalScrollbarHeight(width, contentWidth);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -267,12 +267,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
const scrollDimensions = this._scrollable.getScrollDimensions();
|
||||
const width = scrollDimensions.width;
|
||||
const height = scrollDimensions.height;
|
||||
const scrollWidth = scrollDimensions.scrollWidth;
|
||||
const contentWidth = scrollDimensions.contentWidth;
|
||||
this._scrollable.setScrollDimensions(new EditorScrollDimensions(
|
||||
width,
|
||||
scrollDimensions.contentWidth,
|
||||
height,
|
||||
this._getContentHeight(width, height, scrollWidth)
|
||||
this._getContentHeight(width, height, contentWidth)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { CopyOptions } from 'vs/editor/browser/controller/textAreaInput';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, IActionOptions, ICommandKeybindingsOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorAction, registerEditorAction, Command, MultiCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
@@ -28,171 +28,108 @@ const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge);
|
||||
// privileges to actually perform the action
|
||||
const supportsPaste = (platform.isNative || (!browser.isChrome && document.queryCommandSupported('paste')));
|
||||
|
||||
type ExecCommand = 'cut' | 'copy' | 'paste';
|
||||
|
||||
abstract class ExecCommandAction extends EditorAction {
|
||||
|
||||
private readonly browserCommand: ExecCommand;
|
||||
|
||||
constructor(browserCommand: ExecCommand, opts: IActionOptions) {
|
||||
super(opts);
|
||||
this.browserCommand = browserCommand;
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||
let focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
focusedEditor.trigger('keyboard', this.id, args);
|
||||
return;
|
||||
}
|
||||
|
||||
document.execCommand(this.browserCommand);
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
editor.focus();
|
||||
document.execCommand(this.browserCommand);
|
||||
}
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
}
|
||||
|
||||
class ExecCommandCutAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
export const CutAction = supportsCut ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardCutAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind cut keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
platform.isNative ? {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_X, secondary: [KeyMod.Shift | KeyCode.Delete] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind cut keybindings in the browser,
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
when: EditorContextKeys.writable,
|
||||
order: 1,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
export const CopyAction = supportsCopy ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardCopyAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind copy keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
super('cut', {
|
||||
id: 'editor.action.clipboardCutAction',
|
||||
label: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
alias: 'Cut',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 1
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
|
||||
|
||||
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.run(accessor, editor);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandCopyAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
platform.isNative ? {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyCode.Insert] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind copy keybindings in the browser,
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
order: 2,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
export const PasteAction = supportsPaste ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardPasteAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind paste keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
|
||||
super('copy', {
|
||||
id: 'editor.action.clipboardCopyAction',
|
||||
label: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
alias: 'Copy',
|
||||
precondition: undefined,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 2
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
|
||||
|
||||
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.run(accessor, editor);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandPasteAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
platform.isNative ? {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind paste keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
|
||||
order: 3
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
when: EditorContextKeys.writable,
|
||||
order: 3,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
super('paste', {
|
||||
id: 'editor.action.clipboardPasteAction',
|
||||
label: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
alias: 'Paste',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 3
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
|
||||
order: 3
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
|
||||
class ExecCommandCopyWithSyntaxHighlightingAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super('copy', {
|
||||
super({
|
||||
id: 'editor.action.clipboardCopyWithSyntaxHighlightingAction',
|
||||
label: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', "Copy With Syntax Highlighting"),
|
||||
alias: 'Copy With Syntax Highlighting',
|
||||
@@ -217,20 +154,48 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
|
||||
}
|
||||
|
||||
CopyOptions.forceCopyWithSyntaxHighlighting = true;
|
||||
super.run(accessor, editor);
|
||||
editor.focus();
|
||||
document.execCommand('copy');
|
||||
CopyOptions.forceCopyWithSyntaxHighlighting = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsCut) {
|
||||
registerEditorAction(ExecCommandCutAction);
|
||||
}
|
||||
if (supportsCopy) {
|
||||
registerEditorAction(ExecCommandCopyAction);
|
||||
}
|
||||
if (supportsPaste) {
|
||||
registerEditorAction(ExecCommandPasteAction);
|
||||
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy' | 'paste'): void {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. handle case when focus is in editor.
|
||||
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
if (browserCommand === 'cut' || browserCommand === 'copy') {
|
||||
// Do not execute if there is no selection and empty selection clipboard is off
|
||||
const emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);
|
||||
const selection = focusedEditor.getSelection();
|
||||
if (selection && selection.isEmpty() && !emptySelectionClipboard) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 2. (default) handle case when focus is somewhere else.
|
||||
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
registerExecCommandImpl(CutAction, 'cut');
|
||||
registerExecCommandImpl(CopyAction, 'copy');
|
||||
registerExecCommandImpl(PasteAction, 'paste');
|
||||
|
||||
if (supportsCopyWithSyntaxHighlighting) {
|
||||
registerEditorAction(ExecCommandCopyWithSyntaxHighlightingAction);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,9 @@ class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const emptyCodeActionsResponse = { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||
|
||||
export function getCodeActions(
|
||||
model: ITextModel,
|
||||
rangeOrSelection: Range | Selection,
|
||||
@@ -100,7 +103,7 @@ export function getCodeActions(
|
||||
}
|
||||
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||
return emptyCodeActionsResponse;
|
||||
}
|
||||
|
||||
const filteredActions = (providedCodeActions?.actions || []).filter(action => action && filtersAction(filter, action));
|
||||
@@ -111,7 +114,7 @@ export function getCodeActions(
|
||||
throw err;
|
||||
}
|
||||
onUnexpectedExternalError(err);
|
||||
return { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||
return emptyCodeActionsResponse;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -214,8 +214,8 @@ export class CodeActionModel extends Disposable {
|
||||
}
|
||||
|
||||
const actions = createCancelablePromise(token => getCodeActions(model, trigger.selection, trigger.trigger, Progress.None, token));
|
||||
if (this._progressService && trigger.trigger.type === CodeActionTriggerType.Manual) {
|
||||
this._progressService.showWhile(actions, 250);
|
||||
if (trigger.trigger.type === CodeActionTriggerType.Manual) {
|
||||
this._progressService?.showWhile(actions, 250);
|
||||
}
|
||||
|
||||
this.setState(new CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions));
|
||||
|
||||
@@ -173,7 +173,7 @@ export class ColorDetector extends Disposable implements IEditorContribution {
|
||||
for (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) {
|
||||
const { red, green, blue, alpha } = colorData[i].colorInfo.color;
|
||||
const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);
|
||||
let subKey = hash(rgba).toString(16);
|
||||
let subKey = hash(`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`).toString(16);
|
||||
let color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
|
||||
let key = 'colorBox-' + subKey;
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
// overwritten in subclass
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
this.disposeModel();
|
||||
|
||||
if (!this._editor.hasModel()) {
|
||||
@@ -279,7 +279,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
|
||||
if (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {
|
||||
let selectionSearchString = this.getGlobalBufferTerm();
|
||||
let selectionSearchString = await this.getGlobalBufferTerm();
|
||||
if (selectionSearchString) {
|
||||
stateChanges.searchString = selectionSearchString;
|
||||
}
|
||||
@@ -308,8 +308,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
}
|
||||
|
||||
public start(opts: IFindStartOptions): void {
|
||||
this._start(opts);
|
||||
public start(opts: IFindStartOptions): Promise<void> {
|
||||
return this._start(opts);
|
||||
}
|
||||
|
||||
public moveToNextMatch(): boolean {
|
||||
@@ -353,24 +353,24 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
return false;
|
||||
}
|
||||
|
||||
public getGlobalBufferTerm(): string {
|
||||
public async getGlobalBufferTerm(): Promise<string> {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
return this._clipboardService.readFindTextSync();
|
||||
return this._clipboardService.readFindText();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public setGlobalBufferTerm(text: string) {
|
||||
public async setGlobalBufferTerm(text: string) {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
this._clipboardService.writeFindTextSync(text);
|
||||
await this._clipboardService.writeFindText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +396,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
this._findOptionsWidget = null;
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
if (!this._widget) {
|
||||
this._createFindWidget();
|
||||
}
|
||||
@@ -422,7 +422,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
|
||||
opts.updateSearchScope = updateSearchScope;
|
||||
|
||||
super._start(opts);
|
||||
await super._start(opts);
|
||||
|
||||
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
|
||||
this._widget!.focusReplaceInput();
|
||||
@@ -505,7 +505,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
public async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
let controller = CommonFindController.get(editor);
|
||||
if (controller) {
|
||||
controller.start({
|
||||
@@ -518,7 +518,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
|
||||
controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
return controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,13 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
|
||||
if (!this._state.canNavigateBack()) {
|
||||
// we are beyond the first matched find result
|
||||
// instead of doing nothing, we should refocus the first item
|
||||
const nextMatchRange = this._decorations.matchAfterPosition(before);
|
||||
|
||||
if (nextMatchRange) {
|
||||
this._setCurrentFindMatch(nextMatchRange);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
@@ -350,6 +357,13 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
private _moveToNextMatch(after: Position): void {
|
||||
if (!this._state.canNavigateForward()) {
|
||||
// we are beyond the last matched find result
|
||||
// instead of doing nothing, we should refocus the last item
|
||||
const prevMatchRange = this._decorations.matchBeforePosition(after);
|
||||
|
||||
if (prevMatchRange) {
|
||||
this._setCurrentFindMatch(prevMatchRange);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
|
||||
@@ -52,7 +52,7 @@ export const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDo
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
replaceAll(): void;
|
||||
getGlobalBufferTerm(): string;
|
||||
getGlobalBufferTerm(): Promise<string>;
|
||||
}
|
||||
|
||||
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
|
||||
@@ -224,9 +224,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
|
||||
this._updateToggleSelectionFindButton();
|
||||
}
|
||||
}));
|
||||
this._register(this._codeEditor.onDidFocusEditorWidget(() => {
|
||||
this._register(this._codeEditor.onDidFocusEditorWidget(async () => {
|
||||
if (this._isVisible) {
|
||||
let globalBufferTerm = this._controller.getGlobalBufferTerm();
|
||||
let globalBufferTerm = await this._controller.getGlobalBufferTerm();
|
||||
if (globalBufferTerm && globalBufferTerm !== this._state.searchString) {
|
||||
this._state.change({ searchString: globalBufferTerm }, true);
|
||||
this._findInput.select();
|
||||
|
||||
@@ -39,8 +39,8 @@ export class TestFindController extends CommonFindController {
|
||||
this.hasFocus = false;
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
super._start(opts);
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
await super._start(opts);
|
||||
|
||||
if (opts.shouldFocus !== FindStartFocusAction.NoFocusChange) {
|
||||
this.hasFocus = true;
|
||||
|
||||
@@ -70,7 +70,8 @@ suite('Multicursor selection', () => {
|
||||
remove: (key) => undefined,
|
||||
logStorage: () => undefined,
|
||||
migrate: (toWorkspace) => Promise.resolve(undefined),
|
||||
flush: () => undefined
|
||||
flush: () => undefined,
|
||||
isNew: () => true
|
||||
} as IStorageService);
|
||||
|
||||
test('issue #8817: Cursor position changes when you cancel multicursor', () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .peekview-widget .head {
|
||||
box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
font-size: 13px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty) {
|
||||
@@ -25,6 +26,15 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-editor .peekview-widget .head .peekview-title .dirname {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-editor .peekview-widget .head .peekview-title .filename {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty)::before {
|
||||
content: '-';
|
||||
padding: 0 0.3em;
|
||||
|
||||
@@ -167,7 +167,7 @@ suite('WordOperations', () => {
|
||||
|
||||
test('cursorWordStartLeft', () => {
|
||||
// This is the behaviour observed in Visual Studio, please do not touch test
|
||||
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n');
|
||||
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/ '].join('\n');
|
||||
const [text,] = deserializePipePositions(EXPECTED);
|
||||
const actualStops = testRepeatedActionAndExtractPositions(
|
||||
text,
|
||||
|
||||
@@ -115,9 +115,12 @@ export interface IGlobalEditorOptions {
|
||||
wordBasedSuggestions?: boolean;
|
||||
/**
|
||||
* Controls whether the semanticHighlighting is shown for the languages that support it.
|
||||
* Defaults to true.
|
||||
* true: semanticHighlighting is enabled for all themes
|
||||
* false: semanticHighlighting is disabled for all themes
|
||||
* 'configuredByTheme': semanticHighlighting is controlled by the current color theme's semanticHighlighting setting.
|
||||
* Defaults to 'byTheme'.
|
||||
*/
|
||||
'semanticHighlighting.enabled'?: boolean;
|
||||
'semanticHighlighting.enabled'?: true | false | 'configuredByTheme';
|
||||
/**
|
||||
* Keep peek editors open even when double clicking their content or when hitting `Escape`.
|
||||
* Defaults to false.
|
||||
|
||||
@@ -31,14 +31,14 @@ var RECORDED_EVENTS = [];
|
||||
|
||||
var input = document.getElementById('input');
|
||||
|
||||
var blackListedProps = [
|
||||
var blockedProperties = [
|
||||
'currentTarget',
|
||||
'path',
|
||||
'srcElement',
|
||||
'target',
|
||||
'view'
|
||||
];
|
||||
blackListedProps = blackListedProps.concat([
|
||||
blockedProperties = blockedProperties.concat([
|
||||
'AT_TARGET',
|
||||
'BLUR',
|
||||
'BUBBLING_PHASE',
|
||||
@@ -68,7 +68,7 @@ blackListedProps = blackListedProps.concat([
|
||||
function toSerializable(e) {
|
||||
var r = {};
|
||||
for (var k in e) {
|
||||
if (blackListedProps.indexOf(k) >= 0) {
|
||||
if (blockedProperties.indexOf(k) >= 0) {
|
||||
continue;
|
||||
}
|
||||
if (typeof e[k] === 'function') {
|
||||
@@ -112,4 +112,4 @@ document.getElementById('stop').onclick = function() {
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -781,4 +781,29 @@ suite('TextModelSearch', () => {
|
||||
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('issue #100134. Zero-length matches should properly step over surrogate pairs', () => {
|
||||
// 1[Laptop]1 - there shoud be no matches inside of [Laptop] emoji
|
||||
assertFindMatches('1\uD83D\uDCBB1', '()', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 1],
|
||||
[1, 2, 1, 2],
|
||||
[1, 4, 1, 4],
|
||||
[1, 5, 1, 5],
|
||||
|
||||
]
|
||||
);
|
||||
// 1[Hacker Cat]1 = 1[Cat Face][ZWJ][Laptop]1 - there shoud be matches between emoji and ZWJ
|
||||
// there shoud be no matches inside of [Cat Face] and [Laptop] emoji
|
||||
assertFindMatches('1\uD83D\uDC31\u200D\uD83D\uDCBB1', '()', true, false, null,
|
||||
[
|
||||
[1, 1, 1, 1],
|
||||
[1, 2, 1, 2],
|
||||
[1, 4, 1, 4],
|
||||
[1, 5, 1, 5],
|
||||
[1, 7, 1, 7],
|
||||
[1, 8, 1, 8]
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,4 +104,15 @@ suite('LanguageSelector', function () {
|
||||
let value = score(selector, URI.parse('file:///C:/Users/zlhe/Desktop/test.interface.json'), 'json', true);
|
||||
assert.equal(value, 10);
|
||||
});
|
||||
|
||||
test('Document selector match - platform paths #99938', function () {
|
||||
let selector = {
|
||||
pattern: {
|
||||
base: '/home/user/Desktop',
|
||||
pattern: '*.json'
|
||||
}
|
||||
};
|
||||
let value = score(selector, URI.file('/home/user/Desktop/test.json'), 'json', true);
|
||||
assert.equal(value, 10);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -223,4 +223,11 @@ suite('Editor Modes - Link Computer', () => {
|
||||
' https://foo.bar/[this is foo site] '
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #100353: Link detection stops at &(double-byte)', () => {
|
||||
assertLink(
|
||||
'aa http://tree-mark.chips.jp/レーズン&ベリーミックス aa',
|
||||
' http://tree-mark.chips.jp/レーズン&ベリーミックス '
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -624,17 +624,34 @@ var AMDLoader;
|
||||
script.addEventListener('error', errorEventListener);
|
||||
};
|
||||
BrowserScriptLoader.prototype.load = function (moduleManager, scriptSrc, callback, errorback) {
|
||||
var script = document.createElement('script');
|
||||
script.setAttribute('async', 'async');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
this.attachListeners(script, callback, errorback);
|
||||
script.setAttribute('src', scriptSrc);
|
||||
// Propagate CSP nonce to dynamically created script tag.
|
||||
var cspNonce = moduleManager.getConfig().getOptionsLiteral().cspNonce;
|
||||
if (cspNonce) {
|
||||
script.setAttribute('nonce', cspNonce);
|
||||
if (/^node\|/.test(scriptSrc)) {
|
||||
var opts = moduleManager.getConfig().getOptionsLiteral();
|
||||
var nodeRequire = (opts.nodeRequire || AMDLoader.global.nodeRequire);
|
||||
var pieces = scriptSrc.split('|');
|
||||
var moduleExports_1 = null;
|
||||
try {
|
||||
moduleExports_1 = nodeRequire(pieces[1]);
|
||||
}
|
||||
catch (err) {
|
||||
errorback(err);
|
||||
return;
|
||||
}
|
||||
moduleManager.enqueueDefineAnonymousModule([], function () { return moduleExports_1; });
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
var script = document.createElement('script');
|
||||
script.setAttribute('async', 'async');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
this.attachListeners(script, callback, errorback);
|
||||
script.setAttribute('src', scriptSrc);
|
||||
// Propagate CSP nonce to dynamically created script tag.
|
||||
var cspNonce = moduleManager.getConfig().getOptionsLiteral().cspNonce;
|
||||
if (cspNonce) {
|
||||
script.setAttribute('nonce', cspNonce);
|
||||
}
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
};
|
||||
return BrowserScriptLoader;
|
||||
}());
|
||||
@@ -742,15 +759,15 @@ var AMDLoader;
|
||||
var recorder = moduleManager.getRecorder();
|
||||
if (/^node\|/.test(scriptSrc)) {
|
||||
var pieces = scriptSrc.split('|');
|
||||
var moduleExports_1 = null;
|
||||
var moduleExports_2 = null;
|
||||
try {
|
||||
moduleExports_1 = nodeRequire(pieces[1]);
|
||||
moduleExports_2 = nodeRequire(pieces[1]);
|
||||
}
|
||||
catch (err) {
|
||||
errorback(err);
|
||||
return;
|
||||
}
|
||||
moduleManager.enqueueDefineAnonymousModule([], function () { return moduleExports_1; });
|
||||
moduleManager.enqueueDefineAnonymousModule([], function () { return moduleExports_2; });
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
|
||||
23
src/vs/monaco.d.ts
vendored
23
src/vs/monaco.d.ts
vendored
@@ -1117,9 +1117,12 @@ declare namespace monaco.editor {
|
||||
wordBasedSuggestions?: boolean;
|
||||
/**
|
||||
* Controls whether the semanticHighlighting is shown for the languages that support it.
|
||||
* Defaults to true.
|
||||
* true: semanticHighlighting is enabled for all themes
|
||||
* false: semanticHighlighting is disabled for all themes
|
||||
* 'configuredByTheme': semanticHighlighting is controlled by the current color theme's semanticHighlighting setting.
|
||||
* Defaults to 'byTheme'.
|
||||
*/
|
||||
'semanticHighlighting.enabled'?: boolean;
|
||||
'semanticHighlighting.enabled'?: true | false | 'configuredByTheme';
|
||||
/**
|
||||
* Keep peek editors open even when double clicking their content or when hitting `Escape`.
|
||||
* Defaults to false.
|
||||
@@ -3129,6 +3132,10 @@ declare namespace monaco.editor {
|
||||
* Defaults to false.
|
||||
*/
|
||||
definitionLinkOpensInPeek?: boolean;
|
||||
/**
|
||||
* Controls strikethrough deprecated variables.
|
||||
*/
|
||||
showDeprecated?: boolean;
|
||||
}
|
||||
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
@@ -3949,11 +3956,12 @@ declare namespace monaco.editor {
|
||||
wordWrapMinified = 109,
|
||||
wrappingIndent = 110,
|
||||
wrappingStrategy = 111,
|
||||
editorClassName = 112,
|
||||
pixelRatio = 113,
|
||||
tabFocusMode = 114,
|
||||
layoutInfo = 115,
|
||||
wrappingInfo = 116
|
||||
showDeprecated = 112,
|
||||
editorClassName = 113,
|
||||
pixelRatio = 114,
|
||||
tabFocusMode = 115,
|
||||
layoutInfo = 116,
|
||||
wrappingInfo = 117
|
||||
}
|
||||
export const EditorOptions: {
|
||||
acceptSuggestionOnCommitCharacter: IEditorOption<EditorOption.acceptSuggestionOnCommitCharacter, boolean>;
|
||||
@@ -4049,6 +4057,7 @@ declare namespace monaco.editor {
|
||||
selectOnLineNumbers: IEditorOption<EditorOption.selectOnLineNumbers, boolean>;
|
||||
showFoldingControls: IEditorOption<EditorOption.showFoldingControls, 'always' | 'mouseover'>;
|
||||
showUnused: IEditorOption<EditorOption.showUnused, boolean>;
|
||||
showDeprecated: IEditorOption<EditorOption.showDeprecated, boolean>;
|
||||
snippetSuggestions: IEditorOption<EditorOption.snippetSuggestions, 'none' | 'top' | 'bottom' | 'inline'>;
|
||||
smoothScrolling: IEditorOption<EditorOption.smoothScrolling, boolean>;
|
||||
stopRenderingLineAfter: IEditorOption<EditorOption.stopRenderingLineAfter, number>;
|
||||
|
||||
@@ -97,14 +97,4 @@ export class BrowserClipboardService implements IClipboardService {
|
||||
async hasResources(): Promise<boolean> {
|
||||
return this.resources.length > 0;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
readFindTextSync(): string {
|
||||
return this.findText;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
writeFindTextSync(text: string): void {
|
||||
this.findText = text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,4 @@ export interface IClipboardService {
|
||||
* Find out if resources are copied to the clipboard.
|
||||
*/
|
||||
hasResources(): Promise<boolean>;
|
||||
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
readFindTextSync(): string;
|
||||
|
||||
/** @deprecated */
|
||||
writeFindTextSync(text: string): void;
|
||||
}
|
||||
|
||||
@@ -660,16 +660,7 @@ export class ContextKeyNotRegexExpr implements IContextKeyExpression {
|
||||
export class ContextKeyAndExpr implements IContextKeyExpression {
|
||||
|
||||
public static create(_expr: ReadonlyArray<ContextKeyExpression | null | undefined>): ContextKeyExpression | undefined {
|
||||
const expr = ContextKeyAndExpr._normalizeArr(_expr);
|
||||
if (expr.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (expr.length === 1) {
|
||||
return expr[0];
|
||||
}
|
||||
|
||||
return new ContextKeyAndExpr(expr);
|
||||
return ContextKeyAndExpr._normalizeArr(_expr);
|
||||
}
|
||||
|
||||
public readonly type = ContextKeyExprType.And;
|
||||
@@ -720,7 +711,7 @@ export class ContextKeyAndExpr implements IContextKeyExpression {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static _normalizeArr(arr: ReadonlyArray<ContextKeyExpression | null | undefined>): ContextKeyExpression[] {
|
||||
private static _normalizeArr(arr: ReadonlyArray<ContextKeyExpression | null | undefined>): ContextKeyExpression | undefined {
|
||||
const expr: ContextKeyExpression[] = [];
|
||||
let hasTrue = false;
|
||||
|
||||
@@ -737,7 +728,7 @@ export class ContextKeyAndExpr implements IContextKeyExpression {
|
||||
|
||||
if (e.type === ContextKeyExprType.False) {
|
||||
// anything && false ==> false
|
||||
return [ContextKeyFalseExpr.INSTANCE];
|
||||
return ContextKeyFalseExpr.INSTANCE;
|
||||
}
|
||||
|
||||
if (e.type === ContextKeyExprType.And) {
|
||||
@@ -745,21 +736,48 @@ export class ContextKeyAndExpr implements IContextKeyExpression {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e.type === ContextKeyExprType.Or) {
|
||||
// Not allowed, because we don't have parens!
|
||||
throw new Error(`It is not allowed to have an or expression here due to lack of parens! For example "a && (b||c)" is not supported, use "(a&&b) || (a&&c)" instead.`);
|
||||
}
|
||||
|
||||
expr.push(e);
|
||||
}
|
||||
|
||||
if (expr.length === 0 && hasTrue) {
|
||||
return [ContextKeyTrueExpr.INSTANCE];
|
||||
return ContextKeyTrueExpr.INSTANCE;
|
||||
}
|
||||
|
||||
if (expr.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (expr.length === 1) {
|
||||
return expr[0];
|
||||
}
|
||||
|
||||
expr.sort(cmp);
|
||||
|
||||
return expr;
|
||||
// We must distribute any OR expression because we don't support parens
|
||||
// OR extensions will be at the end (due to sorting rules)
|
||||
while (expr.length > 1) {
|
||||
const lastElement = expr[expr.length - 1];
|
||||
if (lastElement.type !== ContextKeyExprType.Or) {
|
||||
break;
|
||||
}
|
||||
// pop the last element
|
||||
expr.pop();
|
||||
|
||||
// pop the second to last element
|
||||
const secondToLastElement = expr.pop()!;
|
||||
|
||||
// distribute `lastElement` over `secondToLastElement`
|
||||
const resultElement = ContextKeyOrExpr.create(
|
||||
lastElement.expr.map(el => ContextKeyAndExpr.create([el, secondToLastElement]))
|
||||
);
|
||||
|
||||
if (resultElement) {
|
||||
expr.push(resultElement);
|
||||
expr.sort(cmp);
|
||||
}
|
||||
}
|
||||
|
||||
return new ContextKeyAndExpr(expr);
|
||||
}
|
||||
|
||||
public serialize(): string {
|
||||
|
||||
@@ -148,4 +148,18 @@ suite('ContextKeyExpr', () => {
|
||||
testNormalize('isLinux', isLinux ? 'true' : 'false');
|
||||
testNormalize('isWindows', isWindows ? 'true' : 'false');
|
||||
});
|
||||
|
||||
test('issue #101015: distribute OR', () => {
|
||||
function t(expr1: string, expr2: string, expected: string | undefined): void {
|
||||
const e1 = ContextKeyExpr.deserialize(expr1);
|
||||
const e2 = ContextKeyExpr.deserialize(expr2);
|
||||
const actual = ContextKeyExpr.and(e1, e2)?.serialize();
|
||||
assert.strictEqual(actual, expected);
|
||||
}
|
||||
t('a', 'b', 'a && b');
|
||||
t('a || b', 'c', 'a && c || b && c');
|
||||
t('a || b', 'c || d', 'a && c || b && c || a && d || b && d');
|
||||
t('a || b', 'c && d', 'a && c && d || b && c && d');
|
||||
t('a || b', 'c && d || e', 'a && e || b && e || a && c && d || b && c && d');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface IContextViewService extends IContextViewProvider {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): void;
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): IDisposable;
|
||||
hideContextView(data?: any): void;
|
||||
layout(): void;
|
||||
anchorAlignment?: AnchorAlignment;
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
|
||||
import { IContextViewService, IContextViewDelegate } from './contextView';
|
||||
import { ContextView } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
|
||||
export class ContextViewService extends Disposable implements IContextViewService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private currentViewDisposable: IDisposable = Disposable.None;
|
||||
private contextView: ContextView;
|
||||
private container: HTMLElement;
|
||||
|
||||
@@ -32,8 +33,7 @@ export class ContextViewService extends Disposable implements IContextViewServic
|
||||
this.contextView.setContainer(container, !!useFixedPosition);
|
||||
}
|
||||
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): void {
|
||||
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): IDisposable {
|
||||
if (container) {
|
||||
if (container !== this.container) {
|
||||
this.container = container;
|
||||
@@ -47,6 +47,15 @@ export class ContextViewService extends Disposable implements IContextViewServic
|
||||
}
|
||||
|
||||
this.contextView.show(delegate);
|
||||
|
||||
const disposable = toDisposable(() => {
|
||||
if (this.currentViewDisposable === disposable) {
|
||||
this.hideContextView();
|
||||
}
|
||||
});
|
||||
|
||||
this.currentViewDisposable = disposable;
|
||||
return disposable;
|
||||
}
|
||||
|
||||
layout(): void {
|
||||
|
||||
@@ -34,6 +34,10 @@ export interface ICloseSessionEvent {
|
||||
sessionId: string;
|
||||
}
|
||||
|
||||
export interface IOpenExtensionWindowResult {
|
||||
rendererDebugPort?: number;
|
||||
}
|
||||
|
||||
export interface IExtensionHostDebugService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
@@ -52,5 +56,5 @@ export interface IExtensionHostDebugService {
|
||||
terminateSession(sessionId: string, subId?: string): void;
|
||||
readonly onTerminateSession: Event<ITerminateSessionEvent>;
|
||||
|
||||
openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise<void>;
|
||||
openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise<IOpenExtensionWindowResult>;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent, IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent, IExtensionHostDebugService, IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -101,7 +101,7 @@ export class ExtensionHostDebugChannelClient extends Disposable implements IExte
|
||||
return this.channel.listen('terminate');
|
||||
}
|
||||
|
||||
openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise<void> {
|
||||
return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]);
|
||||
openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise<IOpenExtensionWindowResult> {
|
||||
return this.channel.call('openExtensionDevelopmentHostWindow', [args, env, debugRenderer]);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user