Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998 (#7880)

* Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998

* fix pipelines

* fix strict-null-checks

* add missing files
This commit is contained in:
Anthony Dresser
2019-10-21 22:12:22 -07:00
committed by GitHub
parent 7c9be74970
commit 1e22f47304
913 changed files with 18898 additions and 16536 deletions
+5 -4
View File
@@ -21,7 +21,7 @@ exports.assign = function assign(destination, source) {
*
* @param {string[]} modulePaths
* @param {(result, configuration: object) => any} resultCallback
* @param {{ forceEnableDeveloperKeybindings?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options
* @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) {
@@ -58,7 +58,7 @@ exports.load = function (modulePaths, resultCallback, options) {
const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath;
let developerToolsUnbind;
if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) {
developerToolsUnbind = registerDeveloperKeybindings();
developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding);
}
// Correctly inherit the parent's environment
@@ -178,9 +178,10 @@ function parseURLQueryArgs() {
}
/**
* @param {boolean} disallowReloadKeybinding
* @returns {() => void}
*/
function registerDeveloperKeybindings() {
function registerDeveloperKeybindings(disallowReloadKeybinding) {
// @ts-ignore
const ipc = require('electron').ipcRenderer;
@@ -204,7 +205,7 @@ function registerDeveloperKeybindings() {
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) {
} else if (key === RELOAD_KB && !disallowReloadKeybinding) {
ipc.send('vscode:reloadWindow');
}
};
+8 -10
View File
@@ -21,6 +21,7 @@ process.on('SIGPIPE', () => {
//#endregion
//#region Add support for redirecting the loading of node modules
exports.injectNodeModuleLookupPath = function (injectPath) {
if (!injectPath) {
throw new Error('Missing injectPath');
@@ -36,10 +37,8 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
const originalResolveLookupPaths = Module._resolveLookupPaths;
// @ts-ignore
Module._resolveLookupPaths = function (moduleName, parent, newReturn) {
const result = originalResolveLookupPaths(moduleName, parent, newReturn);
const paths = newReturn ? result : result[1];
Module._resolveLookupPaths = function (moduleName, parent) {
const paths = originalResolveLookupPaths(moduleName, parent);
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === nodeModulesPath) {
paths.splice(i, 0, injectPath);
@@ -47,7 +46,7 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
}
}
return result;
return paths;
};
};
//#endregion
@@ -71,11 +70,10 @@ exports.enableASARSupport = function (nodeModulesPath) {
// @ts-ignore
const originalResolveLookupPaths = Module._resolveLookupPaths;
// @ts-ignore
Module._resolveLookupPaths = function (request, parent, newReturn) {
const result = originalResolveLookupPaths(request, parent, newReturn);
const paths = newReturn ? result : result[1];
// @ts-ignore
Module._resolveLookupPaths = function (request, parent) {
const paths = originalResolveLookupPaths(request, parent);
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === NODE_MODULES_PATH) {
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
@@ -83,7 +81,7 @@ exports.enableASARSupport = function (nodeModulesPath) {
}
}
return result;
return paths;
};
};
//#endregion
+263 -98
View File
@@ -12,12 +12,14 @@ const lp = require('./vs/base/node/languagePacks');
perf.mark('main:started');
const path = require('path');
const fs = require('fs');
const os = require('os');
const bootstrap = require('./bootstrap');
const paths = require('./paths');
// @ts-ignore
const product = require('../product.json');
// @ts-ignore
const app = require('electron').app;
const { app, protocol } = require('electron');
// Enable portable support
const portable = bootstrap.configurePortable();
@@ -25,7 +27,7 @@ const portable = bootstrap.configurePortable();
// Enable ASAR support
bootstrap.enableASARSupport();
// Set userData path before app 'ready' event and call to process.chdir
// Set userData path before app 'ready' event
const args = parseCLIArgs();
if (args['nogpu']) { // {{SQL CARBON EDIT}}
@@ -37,32 +39,44 @@ if (args['nogpu']) { // {{SQL CARBON EDIT}}
const userDataPath = getUserDataPath(args);
app.setPath('userData', userDataPath);
// Set logs path before app 'ready' event if running portable
// to ensure that no 'logs' folder is created on disk at a
// location outside of the portable directory
// (https://github.com/microsoft/vscode/issues/56651)
if (portable.isPortable) {
app.setAppLogsPath(path.join(userDataPath, 'logs'));
}
// Update cwd based on environment and platform
setCurrentWorkingDirectory();
// Register custom schemes with privileges
protocol.registerSchemesAsPrivileged([
{ scheme: 'vscode-resource', privileges: { secure: true, supportFetchAPI: true, corsEnabled: true } }
]);
// Global app listeners
registerListeners();
/**
* Support user defined locale
*
* @type {Promise}
*/
let nlsConfiguration = undefined;
const userDefinedLocale = getUserDefinedLocale();
const metaDataFile = path.join(__dirname, 'nls.metadata.json');
userDefinedLocale.then(locale => {
if (locale && !nlsConfiguration) {
nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
}
});
// Cached data
const nodeCachedDataDir = getNodeCachedDir();
// Configure command line switches
configureCommandlineSwitches(args);
// Configure static command line arguments
const argvConfig = configureCommandlineSwitchesSync(args);
/**
* Support user defined locale: load it early before app('ready')
* to have more things running in parallel.
*
* @type {Promise<import('./vs/base/node/languagePacks').NLSConfiguration>} nlsConfig | undefined
*/
let nlsConfigurationPromise = undefined;
const metaDataFile = path.join(__dirname, 'nls.metadata.json');
const locale = getUserDefinedLocale(argvConfig);
if (locale) {
nlsConfigurationPromise = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
}
// Load our code once ready
app.once('ready', function () {
@@ -81,62 +95,35 @@ app.once('ready', function () {
}
});
function onReady() {
/**
* Main startup routine
*
* @param {string | undefined} cachedDataDir
* @param {import('./vs/base/node/languagePacks').NLSConfiguration} nlsConfig
*/
function startup(cachedDataDir, nlsConfig) {
nlsConfig._languagePackSupport = true;
process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig);
process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || '';
// Load main in AMD
perf.mark('willLoadMainBundle');
require('./bootstrap-amd').load('vs/code/electron-main/main', () => {
perf.mark('didLoadMainBundle');
});
}
async function onReady() {
perf.mark('main:appReady');
Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]).then(([cachedDataDir, locale]) => {
if (locale && !nlsConfiguration) {
nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
}
try {
const [cachedDataDir, nlsConfig] = await Promise.all([nodeCachedDataDir.ensureExists(), resolveNlsConfiguration()]);
if (!nlsConfiguration) {
nlsConfiguration = Promise.resolve(undefined);
}
// First, we need to test a user defined locale. If it fails we try the app locale.
// If that fails we fall back to English.
nlsConfiguration.then(nlsConfig => {
const startup = nlsConfig => {
nlsConfig._languagePackSupport = true;
process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig);
process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || '';
// Load main in AMD
perf.mark('willLoadMainBundle');
require('./bootstrap-amd').load('vs/code/electron-main/main', () => {
perf.mark('didLoadMainBundle');
});
};
// We received a valid nlsConfig from a user defined locale
if (nlsConfig) {
startup(nlsConfig);
}
// Try to use the app locale. Please note that the app locale is only
// valid after we have received the app ready event. This is why the
// code is here.
else {
let appLocale = app.getLocale();
if (!appLocale) {
startup({ locale: 'en', availableLanguages: {} });
} else {
// See above the comment about the loader and case sensitiviness
appLocale = appLocale.toLowerCase();
lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale).then(nlsConfig => {
if (!nlsConfig) {
nlsConfig = { locale: appLocale, availableLanguages: {} };
}
startup(nlsConfig);
});
}
}
});
}, console.error);
startup(cachedDataDir, nlsConfig);
} catch (error) {
console.error(error);
}
}
/**
@@ -144,16 +131,147 @@ function onReady() {
*
* @param {ParsedArgs} cliArgs
*/
function configureCommandlineSwitches(cliArgs) {
function configureCommandlineSwitchesSync(cliArgs) {
const SUPPORTED_ELECTRON_SWITCHES = [
// Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791)
app.commandLine.appendSwitch('disable-color-correct-rendering');
// alias from us for --disable-gpu
'disable-hardware-acceleration',
// provided by Electron
'disable-color-correct-rendering'
];
// Read argv config
const argvConfig = readArgvConfigSync();
// Append each flag to Electron
Object.keys(argvConfig).forEach(argvKey => {
if (SUPPORTED_ELECTRON_SWITCHES.indexOf(argvKey) === -1) {
return; // unsupported argv key
}
const argvValue = argvConfig[argvKey];
if (argvValue === true || argvValue === 'true') {
if (argvKey === 'disable-hardware-acceleration') {
app.disableHardwareAcceleration(); // needs to be called explicitly
} else {
app.commandLine.appendArgument(argvKey);
}
} else {
app.commandLine.appendSwitch(argvKey, argvValue);
}
});
// Support JS Flags
const jsFlags = getJSFlags(cliArgs);
if (jsFlags) {
app.commandLine.appendSwitch('--js-flags', jsFlags);
app.commandLine.appendSwitch('js-flags', jsFlags);
}
return argvConfig;
}
function readArgvConfigSync() {
// Read or create the argv.json config file sync before app('ready')
const argvConfigPath = getArgvConfigPath();
let argvConfig;
try {
argvConfig = JSON.parse(stripComments(fs.readFileSync(argvConfigPath).toString()));
} catch (error) {
if (error && error.code === 'ENOENT') {
createDefaultArgvConfigSync(argvConfigPath);
} else {
console.warn(`Unable to read argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`);
}
}
// Fallback to default
if (!argvConfig) {
argvConfig = {
'disable-color-correct-rendering': true // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791)
};
}
return argvConfig;
}
/**
* @param {string} argvConfigPath
*/
function createDefaultArgvConfigSync(argvConfigPath) {
try {
// Ensure argv config parent exists
const argvConfigPathDirname = path.dirname(argvConfigPath);
if (!fs.existsSync(argvConfigPathDirname)) {
fs.mkdirSync(argvConfigPathDirname);
}
// Migrate over legacy locale
const localeConfigPath = path.join(userDataPath, 'User', 'locale.json');
const legacyLocale = getLegacyUserDefinedLocaleSync(localeConfigPath);
if (legacyLocale) {
try {
fs.unlinkSync(localeConfigPath);
} catch (error) {
//ignore
}
}
// Default argv content
const defaultArgvConfigContent = [
'// This configuration file allows to pass permanent command line arguments to VSCode.',
'// Only a subset of arguments is currently supported to reduce the likelyhood of breaking',
'// the installation.',
'//',
'// PLEASE DO NOT CHANGE WITHOUT UNDERSTANDING THE IMPACT',
'//',
'// If the command line argument does not have any values, simply assign',
'// it in the JSON below with a value of \'true\'. Otherwise, put the value',
'// directly.',
'//',
'// If you see rendering issues in VSCode and have a better experience',
'// with software rendering, you can configure this by adding:',
'//',
'// \'disable-hardware-acceleration\': true',
'//',
'// NOTE: Changing this file requires a restart of VSCode.',
'{',
' // Enabled by default by VSCode to resolve color issues in the renderer',
' // See https://github.com/Microsoft/vscode/issues/51791 for details',
' "disable-color-correct-rendering": true'
];
if (legacyLocale) {
defaultArgvConfigContent[defaultArgvConfigContent.length - 1] = `${defaultArgvConfigContent[defaultArgvConfigContent.length - 1]},`; // append trailing ","
defaultArgvConfigContent.push('');
defaultArgvConfigContent.push(' // Display language of VSCode');
defaultArgvConfigContent.push(` "locale": "${legacyLocale}"`);
}
defaultArgvConfigContent.push('}');
// Create initial argv.json with default content
fs.writeFileSync(argvConfigPath, defaultArgvConfigContent.join('\n'));
} catch (error) {
console.error(`Unable to create argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`);
}
}
function getArgvConfigPath() {
const vscodePortable = process.env['VSCODE_PORTABLE'];
if (vscodePortable) {
return path.join(vscodePortable, 'argv.json');
}
let dataFolderName = product.dataFolderName;
if (process.env['VSCODE_DEV']) {
dataFolderName = `${dataFolderName}-dev`;
}
return path.join(os.homedir(), dataFolderName, 'argv.json');
}
/**
@@ -256,7 +374,7 @@ function registerListeners() {
}
/**
* @returns {{ ensureExists: () => Promise<string | void> }}
* @returns {{ ensureExists: () => Promise<string | undefined> }}
*/
function getNodeCachedDir() {
return new class {
@@ -265,8 +383,14 @@ function getNodeCachedDir() {
this.value = this._compute();
}
ensureExists() {
return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ });
async ensureExists() {
try {
await bootstrap.mkdirp(this.value);
return this.value;
} catch (error) {
// ignore
}
}
_compute() {
@@ -291,6 +415,41 @@ function getNodeCachedDir() {
}
//#region NLS Support
/**
* Resolve the NLS configuration
*
* @return {Promise<import('./vs/base/node/languagePacks').NLSConfiguration>}
*/
async function resolveNlsConfiguration() {
// First, we need to test a user defined locale. If it fails we try the app locale.
// If that fails we fall back to English.
let nlsConfiguration = nlsConfigurationPromise ? await nlsConfigurationPromise : undefined;
if (!nlsConfiguration) {
// Try to use the app locale. Please note that the app locale is only
// valid after we have received the app ready event. This is why the
// code is here.
let appLocale = app.getLocale();
if (!appLocale) {
nlsConfiguration = { locale: 'en', availableLanguages: {} };
} else {
// See above the comment about the loader and case sensitiviness
appLocale = appLocale.toLowerCase();
nlsConfiguration = await lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale);
if (!nlsConfiguration) {
nlsConfiguration = { locale: appLocale, availableLanguages: {} };
}
}
} else {
// We received a valid nlsConfig from a user defined locale
}
return nlsConfiguration;
}
/**
* @param {string} content
* @returns {string}
@@ -319,30 +478,36 @@ function stripComments(content) {
});
}
// Language tags are case insensitive however an amd loader is case sensitive
// To make this work on case preserving & insensitive FS we do the following:
// the language bundles have lower case language tags and we always lower case
// the locale we receive from the user or OS.
/**
* @returns {Promise<string>}
* Language tags are case insensitive however an amd loader is case sensitive
* To make this work on case preserving & insensitive FS we do the following:
* the language bundles have lower case language tags and we always lower case
* the locale we receive from the user or OS.
*
* @param {{ locale: string | undefined; }} argvConfig
* @returns {string | undefined}
*/
function getUserDefinedLocale() {
function getUserDefinedLocale(argvConfig) {
const locale = args['locale'];
if (locale) {
return Promise.resolve(locale.toLowerCase());
return locale.toLowerCase(); // a directly provided --locale always wins
}
const localeConfig = path.join(userDataPath, 'User', 'locale.json');
return bootstrap.readFile(localeConfig).then(content => {
content = stripComments(content);
try {
const value = JSON.parse(content).locale;
return value && typeof value === 'string' ? value.toLowerCase() : undefined;
} catch (e) {
return undefined;
}
}, () => {
return undefined;
});
return argvConfig.locale && typeof argvConfig.locale === 'string' ? argvConfig.locale.toLowerCase() : undefined;
}
/**
* @param {string} localeConfigPath
* @returns {string | undefined}
*/
function getLegacyUserDefinedLocaleSync(localeConfigPath) {
try {
const content = stripComments(fs.readFileSync(localeConfigPath).toString());
const value = JSON.parse(content).locale;
return value && typeof value === 'string' ? value.toLowerCase() : undefined;
} catch (error) {
// ignore
}
}
//#endregion
@@ -131,22 +131,22 @@ export class DropdownList extends Dropdown {
}
protected applyStyles(): void {
const background = this.backgroundColor ? this.backgroundColor.toString() : null;
const foreground = this.foregroundColor ? this.foregroundColor.toString() : null;
const border = this.borderColor ? this.borderColor.toString() : null;
const background = this.backgroundColor ? this.backgroundColor.toString() : '';
const foreground = this.foregroundColor ? this.foregroundColor.toString() : '';
const border = this.borderColor ? this.borderColor.toString() : '';
this.applyStylesOnElement(this._contentContainer, background, foreground, border);
if (this.label) {
this.applyStylesOnElement(this.element, background, foreground, border);
}
}
private applyStylesOnElement(element: HTMLElement, background: string | null, foreground: string | null, border: string | null): void {
private applyStylesOnElement(element: HTMLElement, background: string, foreground: string, border: string): void {
if (element) {
element.style.backgroundColor = background;
element.style.color = foreground;
element.style.borderWidth = border ? '1px' : null;
element.style.borderStyle = border ? 'solid' : null;
element.style.borderWidth = border ? '1px' : '';
element.style.borderStyle = border ? 'solid' : '';
element.style.borderColor = border;
}
}
+3 -3
View File
@@ -120,7 +120,7 @@ export class ListBox extends SelectBox {
this.selectElement.style.border = `1px solid ${this.selectBorder}`;
} else if (this.message) {
const styles = this.stylesForType(this.message.type);
this.selectElement.style.border = styles.border ? `1px solid ${styles.border}` : null;
this.selectElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
}
}
@@ -224,8 +224,8 @@ export class ListBox extends SelectBox {
dom.addClass(spanElement, this.classForType(this.message.type));
const styles = this.stylesForType(this.message.type);
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : null;
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : null;
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
dom.append(div, spanElement);
}
@@ -224,8 +224,8 @@ export class SelectBox extends vsSelectBox {
dom.addClass(spanElement, this.classForType(message.type));
const styles = this.stylesForType(message.type);
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : null;
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : null;
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
dom.append(div, spanElement);
@@ -227,7 +227,7 @@ export class Dropdown extends Disposable {
}
private _showList(): void {
if (this._input.isEnabled) {
if (this._input.isEnabled()) {
this._onFocus.fire();
this._filter.filterString = '';
this.contextViewService.showContextView({
@@ -297,7 +297,7 @@ export class Dropdown extends Disposable {
style(style: IListStyles & IInputBoxStyles & IDropdownStyles) {
this._tree.style(style);
this._input.style(style);
this._treeContainer.style.backgroundColor = style.contextBackground ? style.contextBackground.toString() : null;
this._treeContainer.style.backgroundColor = style.contextBackground ? style.contextBackground.toString() : '';
this._treeContainer.style.outline = `1px solid ${style.contextBorder || this._options.contextBorder}`;
}
@@ -29,10 +29,6 @@ export interface TitledFormItemLayout {
isGroupLabel?: boolean;
}
export interface FormLayout {
width: number;
}
class FormItem {
constructor(public descriptor: IComponentDescriptor, public config: TitledFormItemLayout) { }
}
@@ -108,7 +108,6 @@ export default class WebViewComponent extends ComponentBase implements IComponen
if (this._webview && this.html) {
this._renderedHtml = this.html;
this._webview.html = this._renderedHtml;
this._webview.layout();
}
}
@@ -142,7 +141,6 @@ export default class WebViewComponent extends ComponentBase implements IComponen
this._ready.then(() => {
let element = <HTMLElement>this._el.nativeElement;
element.style.position = this.position;
this._webview.layout();
});
}
}
@@ -53,7 +53,7 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo
}
public layout(): void {
this._webview.layout();
// no op
}
public get id(): string {
@@ -80,7 +80,6 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo
this._html = html;
if (this._webview) {
this._webview.html = html;
this._webview.layout();
}
}
@@ -113,6 +112,5 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo
if (this._html) {
this._webview.html = this._html;
}
this._webview.layout();
}
}
@@ -60,7 +60,6 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget,
this._html = html;
if (this._webview) {
this._webview.html = html;
this._webview.layout();
}
}
@@ -81,7 +80,7 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget,
}
public layout(): void {
this._webview.layout();
// no op
}
public sendMessage(message: string): void {
@@ -111,6 +110,5 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget,
if (this._html) {
this._webview.html = this._html;
}
this._webview.layout();
}
}
@@ -43,14 +43,7 @@ export class BareResultsGridInfo extends BareFontInfo {
protected constructor(fontInfo: BareFontInfo, opts: {
cellPadding: number | number[];
}) {
super({
zoomLevel: fontInfo.zoomLevel,
fontFamily: fontInfo.fontFamily,
fontWeight: fontInfo.fontWeight,
fontSize: fontInfo.fontSize,
lineHeight: fontInfo.lineHeight,
letterSpacing: fontInfo.letterSpacing
});
super(fontInfo);
this.cellPadding = opts.cellPadding;
}
}
@@ -25,6 +25,7 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
class TestEnvironmentService implements IWorkbenchEnvironmentService {
argvResource: URI;
userDataSyncLogResource: URI;
settingsSyncPreviewResource: URI;
webviewExternalEndpoint: string;
+1309 -452
View File
File diff suppressed because it is too large Load Diff
+48 -3
View File
@@ -82,6 +82,16 @@ declare module 'xterm' {
*/
drawBoldTextInBrightColors?: boolean;
/**
* The modifier key hold to multiply scroll speed.
*/
fastScrollModifier?: 'alt' | 'ctrl' | 'shift' | undefined;
/**
* The scroll speed multiplier used for fast scrolling.
*/
fastScrollSensitivity?: number;
/**
* The font size used to render text.
*/
@@ -173,6 +183,11 @@ declare module 'xterm' {
*/
scrollback?: number;
/**
* The scrolling speed multiplier used for adjusting normal scrolling speed.
*/
scrollSensitivity?: number;
/**
* The size of tab stops in the terminal.
*/
@@ -269,7 +284,7 @@ declare module 'xterm' {
/**
* A callback that fires when the mouse hovers over a link for a moment.
*/
tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void;
tooltipCallback?: (event: MouseEvent, uri: string, location: IViewportRange) => boolean | void;
/**
* A callback that fires when the mouse leaves a link. Note that this can
@@ -352,12 +367,12 @@ declare module 'xterm' {
/**
* The element containing the terminal.
*/
readonly element: HTMLElement;
readonly element: HTMLElement | undefined;
/**
* The textarea that accepts input for the terminal.
*/
readonly textarea: HTMLTextAreaElement;
readonly textarea: HTMLTextAreaElement | undefined;
/**
* The number of rows in the terminal's viewport. Use
@@ -842,6 +857,36 @@ declare module 'xterm' {
endRow: number;
}
/**
* An object representing a range within the viewport of the terminal.
*/
interface IViewportRange {
/**
* The start cell of the range.
*/
start: IViewportCellPosition;
/**
* The end cell of the range.
*/
end: IViewportCellPosition;
}
/**
* An object representing a cell position within the viewport of the terminal.
*/
interface IViewportCellPosition {
/**
* The column of the cell. Note that this is 1-based; the first column is column 1.
*/
col: number;
/**
* The row of the cell. Note that this is 1-based; the first row is row 1.
*/
row: number;
}
/**
* Represents a terminal buffer.
*/
+1
View File
@@ -25,6 +25,7 @@ export class ContextSubMenu extends SubmenuAction {
export interface IContextMenuDelegate {
getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; };
getActions(): ReadonlyArray<IAction | ContextSubMenu>;
getCheckedActionsRepresentation?(action: IAction): 'radio' | 'checkbox';
getActionViewItem?(action: IAction): IActionViewItem | undefined;
getActionsContext?(event?: IContextMenuEvent): any;
getKeyBinding?(action: IAction): ResolvedKeybinding | undefined;
+10
View File
@@ -18,6 +18,7 @@ export class FastDomNode<T extends HTMLElement> {
private _fontFamily: string;
private _fontWeight: string;
private _fontSize: number;
private _fontFeatureSettings: string;
private _lineHeight: number;
private _letterSpacing: number;
private _className: string;
@@ -38,6 +39,7 @@ export class FastDomNode<T extends HTMLElement> {
this._fontFamily = '';
this._fontWeight = '';
this._fontSize = -1;
this._fontFeatureSettings = '';
this._lineHeight = -1;
this._letterSpacing = -100;
this._className = '';
@@ -135,6 +137,14 @@ export class FastDomNode<T extends HTMLElement> {
this.domNode.style.fontSize = this._fontSize + 'px';
}
public setFontFeatureSettings(fontFeatureSettings: string): void {
if (this._fontFeatureSettings === fontFeatureSettings) {
return;
}
this._fontFeatureSettings = fontFeatureSettings;
this.domNode.style.fontFeatureSettings = this._fontFeatureSettings;
}
public setLineHeight(lineHeight: number): void {
if (this._lineHeight === lineHeight) {
return;
+34 -29
View File
@@ -152,8 +152,16 @@ export class StandardWheelEvent {
this.deltaX = deltaX;
if (e) {
if (e.type === 'wheel') {
// Old (deprecated) wheel events
let e1 = <IWebKitMouseWheelEvent><any>e;
let e2 = <IGeckoMouseWheelEvent><any>e;
// vertical delta scroll
if (typeof e1.wheelDeltaY !== 'undefined') {
this.deltaY = e1.wheelDeltaY / 120;
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
this.deltaY = -e2.detail / 3;
} else if (e.type === 'wheel') {
// Modern wheel event
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
const ev = <WheelEvent><unknown>e;
@@ -161,39 +169,36 @@ export class StandardWheelEvent {
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
// the deltas are expressed in lines
this.deltaY = -e.deltaY;
this.deltaX = -e.deltaX;
} else {
this.deltaY = -e.deltaY / 40;
}
}
// horizontal delta scroll
if (typeof e1.wheelDeltaX !== 'undefined') {
if (browser.isSafari && platform.isWindows) {
this.deltaX = - (e1.wheelDeltaX / 120);
} else {
this.deltaX = e1.wheelDeltaX / 120;
}
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
this.deltaX = -e.detail / 3;
} else if (e.type === 'wheel') {
// Modern wheel event
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
const ev = <WheelEvent><unknown>e;
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
// the deltas are expressed in lines
this.deltaX = -e.deltaX;
} else {
this.deltaX = -e.deltaX / 40;
}
}
} else {
// Old (deprecated) wheel events
let e1 = <IWebKitMouseWheelEvent><any>e;
let e2 = <IGeckoMouseWheelEvent><any>e;
// vertical delta scroll
if (typeof e1.wheelDeltaY !== 'undefined') {
this.deltaY = e1.wheelDeltaY / 120;
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
this.deltaY = -e2.detail / 3;
}
// horizontal delta scroll
if (typeof e1.wheelDeltaX !== 'undefined') {
if (browser.isSafari && platform.isWindows) {
this.deltaX = - (e1.wheelDeltaX / 120);
} else {
this.deltaX = e1.wheelDeltaX / 120;
}
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
this.deltaX = -e.detail / 3;
}
// Assume a vertical scroll if nothing else worked
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
this.deltaY = e.wheelDelta / 120;
}
// Assume a vertical scroll if nothing else worked
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
this.deltaY = e.wheelDelta / 120;
}
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ export class Gesture extends Disposable {
private static readonly SCROLL_FRICTION = -0.005;
private static INSTANCE: Gesture;
private static HOLD_DELAY = 700;
private static readonly HOLD_DELAY = 700;
private dispatched = false;
private targets: HTMLElement[];
@@ -50,12 +50,6 @@
margin-right: 4px;
}
.monaco-action-bar .action-label.octicon {
font-size: 15px;
line-height: 35px;
text-align: center;
}
.monaco-action-bar .action-item.disabled .action-label,
.monaco-action-bar .action-item.disabled .action-label:hover {
opacity: 0.4;
+68 -45
View File
@@ -33,11 +33,12 @@ export interface IBaseActionViewItemOptions {
export class BaseActionViewItem extends Disposable implements IActionViewItem {
element?: HTMLElement;
element: HTMLElement | undefined;
_context: any;
_action: IAction;
private _actionRunner!: IActionRunner;
private _actionRunner: IActionRunner | undefined;
constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) {
super();
@@ -81,12 +82,16 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
}
}
set actionRunner(actionRunner: IActionRunner) {
this._actionRunner = actionRunner;
get actionRunner(): IActionRunner {
if (!this._actionRunner) {
this._actionRunner = this._register(new ActionRunner());
}
return this._actionRunner;
}
get actionRunner(): IActionRunner {
return this._actionRunner;
set actionRunner(actionRunner: IActionRunner) {
this._actionRunner = actionRunner;
}
getAction(): IAction {
@@ -102,7 +107,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
}
render(container: HTMLElement): void {
this.element = container;
const element = this.element = container;
this._register(Gesture.addTarget(container));
const enableDragging = this.options && this.options.draggable;
@@ -110,19 +115,19 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
container.draggable = true;
}
this._register(DOM.addDisposableListener(this.element, EventType.Tap, e => this.onClick(e)));
this._register(DOM.addDisposableListener(element, EventType.Tap, e => this.onClick(e)));
this._register(DOM.addDisposableListener(this.element, DOM.EventType.MOUSE_DOWN, e => {
this._register(DOM.addDisposableListener(element, DOM.EventType.MOUSE_DOWN, e => {
if (!enableDragging) {
DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
}
if (this._action.enabled && e.button === 0 && this.element) {
DOM.addClass(this.element, 'active');
if (this._action.enabled && e.button === 0) {
DOM.addClass(element, 'active');
}
}));
this._register(DOM.addDisposableListener(this.element, DOM.EventType.CLICK, e => {
this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => {
DOM.EventHelper.stop(e, true);
// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
// > Writing to the clipboard
@@ -139,14 +144,14 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
}
}));
this._register(DOM.addDisposableListener(this.element, DOM.EventType.DBLCLICK, e => {
this._register(DOM.addDisposableListener(element, DOM.EventType.DBLCLICK, e => {
DOM.EventHelper.stop(e, true);
}));
[DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(event => {
this._register(DOM.addDisposableListener(this.element!, event, e => {
this._register(DOM.addDisposableListener(element, event, e => {
DOM.EventHelper.stop(e);
DOM.removeClass(this.element!, 'active');
DOM.removeClass(element, 'active');
}));
});
}
@@ -165,7 +170,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
}
}
this._actionRunner.run(this._action, context);
this.actionRunner.run(this._action, context);
}
focus(): void {
@@ -219,7 +224,6 @@ export class Separator extends Action {
constructor(label?: string) {
super(Separator.ID, label, label ? 'separator text' : 'separator');
this.checked = false;
this.radio = false;
this.enabled = false;
}
}
@@ -232,7 +236,7 @@ export interface IActionViewItemOptions extends IBaseActionViewItemOptions {
export class ActionViewItem extends BaseActionViewItem {
protected label!: HTMLElement;
protected label: HTMLElement | undefined;
protected options: IActionViewItemOptions;
private cssClass?: string;
@@ -252,13 +256,17 @@ export class ActionViewItem extends BaseActionViewItem {
if (this.element) {
this.label = DOM.append(this.element, DOM.$('a.action-label'));
}
if (this._action.id === Separator.ID) {
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
} else {
if (this.options.isMenu) {
this.label.setAttribute('role', 'menuitem');
if (this.label) {
if (this._action.id === Separator.ID) {
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
} else {
this.label.setAttribute('role', 'button');
if (this.options.isMenu) {
this.label.setAttribute('role', 'menuitem');
} else {
this.label.setAttribute('role', 'button');
}
}
}
@@ -276,11 +284,13 @@ export class ActionViewItem extends BaseActionViewItem {
focus(): void {
super.focus();
this.label.focus();
if (this.label) {
this.label.focus();
}
}
updateLabel(): void {
if (this.options.label) {
if (this.options.label && this.label) {
this.label.textContent = this.getAction().label;
}
}
@@ -299,52 +309,65 @@ export class ActionViewItem extends BaseActionViewItem {
}
}
if (title) {
if (title && this.label) {
this.label.title = title;
}
}
updateClass(): void {
if (this.cssClass) {
if (this.cssClass && this.label) {
DOM.removeClasses(this.label, this.cssClass);
}
if (this.options.icon) {
this.cssClass = this.getAction().class;
DOM.addClass(this.label, 'codicon');
if (this.cssClass) {
DOM.addClasses(this.label, this.cssClass);
if (this.label) {
DOM.addClass(this.label, 'codicon');
if (this.cssClass) {
DOM.addClasses(this.label, this.cssClass);
}
}
this.updateEnabled();
} else {
DOM.removeClass(this.label, 'codicon');
if (this.label) {
DOM.removeClass(this.label, 'codicon');
}
}
}
updateEnabled(): void {
if (this.getAction().enabled) {
this.label.removeAttribute('aria-disabled');
if (this.label) {
this.label.removeAttribute('aria-disabled');
DOM.removeClass(this.label, 'disabled');
this.label.tabIndex = 0;
}
if (this.element) {
DOM.removeClass(this.element, 'disabled');
}
DOM.removeClass(this.label, 'disabled');
this.label.tabIndex = 0;
} else {
this.label.setAttribute('aria-disabled', 'true');
if (this.label) {
this.label.setAttribute('aria-disabled', 'true');
DOM.addClass(this.label, 'disabled');
DOM.removeTabIndexAndUpdateFocus(this.label);
}
if (this.element) {
DOM.addClass(this.element, 'disabled');
}
DOM.addClass(this.label, 'disabled');
DOM.removeTabIndexAndUpdateFocus(this.label);
}
}
updateChecked(): void {
if (this.getAction().checked) {
DOM.addClass(this.label, 'checked');
} else {
DOM.removeClass(this.label, 'checked');
if (this.label) {
if (this.getAction().checked) {
DOM.addClass(this.label, 'checked');
} else {
DOM.removeClass(this.label, 'checked');
}
}
}
}
@@ -745,9 +768,9 @@ export class ActionBar extends Disposable implements IActionRunner {
this.updateFocus(true);
}
protected updateFocus(fromRight?: boolean): void {
protected updateFocus(fromRight?: boolean, preventScroll?: boolean): void {
if (typeof this.focusedItem === 'undefined') {
this.actionsList.focus();
this.actionsList.focus({ preventScroll });
}
for (let i = 0; i < this.viewItems.length; i++) {
@@ -759,7 +782,7 @@ export class ActionBar extends Disposable implements IActionRunner {
if (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) {
actionViewItem.focus(fromRight);
} else {
this.actionsList.focus();
this.actionsList.focus({ preventScroll });
}
}
} else {
+5 -5
View File
@@ -79,7 +79,7 @@ export class Button extends Disposable {
this._register(DOM.addDisposableListener(this._element, DOM.EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
let eventHandled = false;
if (this.enabled && event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
if (this.enabled && (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) {
this._onDidClick.fire(e);
eventHandled = true;
} else if (event.equals(KeyCode.Escape)) {
@@ -129,15 +129,15 @@ export class Button extends Disposable {
// {{SQL CARBON EDIT}} -- removed 'private' access modifier @todo anthonydresser 4/12/19 things needs investigation whether we need this
applyStyles(): void {
if (this._element) {
const background = this.buttonBackground ? this.buttonBackground.toString() : null;
const background = this.buttonBackground ? this.buttonBackground.toString() : '';
const foreground = this.buttonForeground ? this.buttonForeground.toString() : null;
const border = this.buttonBorder ? this.buttonBorder.toString() : null;
const border = this.buttonBorder ? this.buttonBorder.toString() : '';
this._element.style.color = foreground;
this._element.style.backgroundColor = background;
this._element.style.borderWidth = border ? '1px' : null;
this._element.style.borderStyle = border ? 'solid' : null;
this._element.style.borderWidth = border ? '1px' : '';
this._element.style.borderStyle = border ? 'solid' : '';
this._element.style.borderColor = border;
}
}
+4 -4
View File
@@ -38,7 +38,7 @@ const defaultOpts = {
export class CheckboxActionViewItem extends BaseActionViewItem {
private checkbox!: Checkbox;
private checkbox: Checkbox | undefined;
private readonly disposables = new DisposableStore();
render(container: HTMLElement): void {
@@ -51,7 +51,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
title: this._action.label
});
this.disposables.add(this.checkbox);
this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox!.checked, this));
this.disposables.add(this.checkbox.onChange(() => this._action.checked = !!this.checkbox && this.checkbox.checked, this));
this.element.appendChild(this.checkbox.domNode);
}
@@ -219,7 +219,7 @@ export class SimpleCheckbox extends Widget {
protected applyStyles(): void {
this.domNode.style.color = this.styles.checkboxForeground ? this.styles.checkboxForeground.toString() : null;
this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : null;
this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : null;
this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : '';
this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : '';
}
}
@@ -10,5 +10,5 @@
}
.codicon-animation-spin {
animation: octicon-spin 1.5s linear infinite;
animation: codicon-spin 1.5s linear infinite;
}
@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?3b584136fb1f0186a1ee578cdcb5240b") format("truetype");
src: url("./codicon.ttf?10ac421d405314bb3250169d97fc2c62") format("truetype");
}
.codicon[class*='codicon-'] {
@@ -54,6 +54,7 @@
.codicon-star:before { content: "\ea6a" }
.codicon-star-add:before { content: "\ea6a" }
.codicon-star-delete:before { content: "\ea6a" }
.codicon-star-empty:before { content: "\ea6a" }
.codicon-comment:before { content: "\ea6b" }
.codicon-comment-add:before { content: "\ea6b" }
.codicon-alert:before { content: "\ea6c" }
@@ -69,7 +70,6 @@
.codicon-eye-watch:before { content: "\ea70" }
.codicon-circle-filled:before { content: "\ea71" }
.codicon-primitive-dot:before { content: "\ea71" }
.codicon-stop:before { content: "\ea72" }
.codicon-primitive-square:before { content: "\ea72" }
.codicon-edit:before { content: "\ea73" }
.codicon-pencil:before { content: "\ea73" }
@@ -103,253 +103,264 @@
.codicon-file-add:before { content: "\ea7f" }
.codicon-new-folder:before { content: "\ea80" }
.codicon-file-directory-create:before { content: "\ea80" }
.codicon-Vector:before { content: "\f101" }
.codicon-activate-breakpoints:before { content: "\f102" }
.codicon-archive:before { content: "\f103" }
.codicon-array:before { content: "\f104" }
.codicon-arrow-both:before { content: "\f105" }
.codicon-arrow-down:before { content: "\f106" }
.codicon-arrow-left:before { content: "\f107" }
.codicon-arrow-right:before { content: "\f108" }
.codicon-arrow-small-down:before { content: "\f109" }
.codicon-arrow-small-left:before { content: "\f10a" }
.codicon-arrow-small-right:before { content: "\f10b" }
.codicon-arrow-small-up:before { content: "\f10c" }
.codicon-arrow-up:before { content: "\f10d" }
.codicon-bell:before { content: "\f10e" }
.codicon-bold:before { content: "\f10f" }
.codicon-book:before { content: "\f110" }
.codicon-bookmark:before { content: "\f111" }
.codicon-boolean:before { content: "\f112" }
.codicon-breakpoint-conditional-unverified:before { content: "\f113" }
.codicon-breakpoint-conditional:before { content: "\f114" }
.codicon-breakpoint-data-unverified:before { content: "\f115" }
.codicon-breakpoint-data:before { content: "\f116" }
.codicon-breakpoint-log-unverified:before { content: "\f117" }
.codicon-breakpoint-log:before { content: "\f118" }
.codicon-briefcase:before { content: "\f119" }
.codicon-broadcast:before { content: "\f11a" }
.codicon-browser:before { content: "\f11b" }
.codicon-bug:before { content: "\f11c" }
.codicon-calendar:before { content: "\f11d" }
.codicon-case-sensitive:before { content: "\f11e" }
.codicon-check:before { content: "\f11f" }
.codicon-checklist:before { content: "\f120" }
.codicon-chevron-down:before { content: "\f121" }
.codicon-chevron-left:before { content: "\f122" }
.codicon-chevron-right:before { content: "\f123" }
.codicon-chevron-up:before { content: "\f124" }
.codicon-circle-outline:before { content: "\f125" }
.codicon-circle-slash:before { content: "\f126" }
.codicon-circuit-board:before { content: "\f127" }
.codicon-class:before { content: "\f128" }
.codicon-clear-all:before { content: "\f129" }
.codicon-clippy:before { content: "\f12a" }
.codicon-close-all:before { content: "\f12b" }
.codicon-cloud-download:before { content: "\f12c" }
.codicon-cloud-upload:before { content: "\f12d" }
.codicon-code:before { content: "\f12e" }
.codicon-collapse-all:before { content: "\f12f" }
.codicon-color-mode:before { content: "\f130" }
.codicon-color:before { content: "\f131" }
.codicon-comment-discussion:before { content: "\f132" }
.codicon-compare-changes:before { content: "\f133" }
.codicon-console:before { content: "\f134" }
.codicon-constant:before { content: "\f135" }
.codicon-continue:before { content: "\f136" }
.codicon-credit-card:before { content: "\f137" }
.codicon-current-and-breakpoint:before { content: "\f138" }
.codicon-current:before { content: "\f139" }
.codicon-dash:before { content: "\f13a" }
.codicon-dashboard:before { content: "\f13b" }
.codicon-database:before { content: "\f13c" }
.codicon-debug:before { content: "\f13d" }
.codicon-device-camera-video:before { content: "\f13e" }
.codicon-device-camera:before { content: "\f13f" }
.codicon-device-mobile:before { content: "\f140" }
.codicon-diff-added:before { content: "\f141" }
.codicon-diff-ignored:before { content: "\f142" }
.codicon-diff-modified:before { content: "\f143" }
.codicon-diff-removed:before { content: "\f144" }
.codicon-diff-renamed:before { content: "\f145" }
.codicon-diff:before { content: "\f146" }
.codicon-discard:before { content: "\f147" }
.codicon-disconnect-:before { content: "\f148" }
.codicon-editor-layout:before { content: "\f149" }
.codicon-ellipsis:before { content: "\f14a" }
.codicon-empty-window:before { content: "\f14b" }
.codicon-enumerator-member:before { content: "\f14c" }
.codicon-enumerator:before { content: "\f14d" }
.codicon-error:before { content: "\f14e" }
.codicon-event:before { content: "\f14f" }
.codicon-exclude:before { content: "\f150" }
.codicon-extensions:before { content: "\f151" }
.codicon-eye-closed:before { content: "\f152" }
.codicon-field:before { content: "\f153" }
.codicon-file-binary:before { content: "\f154" }
.codicon-file-code:before { content: "\f155" }
.codicon-file-media:before { content: "\f156" }
.codicon-file-pdf:before { content: "\f157" }
.codicon-file-submodule:before { content: "\f158" }
.codicon-file-symlink-directory:before { content: "\f159" }
.codicon-file-symlink-file:before { content: "\f15a" }
.codicon-file-zip:before { content: "\f15b" }
.codicon-files:before { content: "\f15c" }
.codicon-filter:before { content: "\f15d" }
.codicon-flame:before { content: "\f15e" }
.codicon-fold-down:before { content: "\f15f" }
.codicon-fold-up:before { content: "\f160" }
.codicon-fold:before { content: "\f161" }
.codicon-folder-active:before { content: "\f162" }
.codicon-folder-opened:before { content: "\f163" }
.codicon-folder:before { content: "\f164" }
.codicon-gear:before { content: "\f165" }
.codicon-gift:before { content: "\f166" }
.codicon-gist-secret:before { content: "\f167" }
.codicon-gist:before { content: "\f168" }
.codicon-git-commit:before { content: "\f169" }
.codicon-git-compare:before { content: "\f16a" }
.codicon-git-merge:before { content: "\f16b" }
.codicon-github-action:before { content: "\f16c" }
.codicon-github-alt:before { content: "\f16d" }
.codicon-github:before { content: "\f16e" }
.codicon-globe:before { content: "\f16f" }
.codicon-go-to-file:before { content: "\f170" }
.codicon-grabber:before { content: "\f171" }
.codicon-graph:before { content: "\f172" }
.codicon-gripper:before { content: "\f173" }
.codicon-heart:before { content: "\f174" }
.codicon-history:before { content: "\f175" }
.codicon-home:before { content: "\f176" }
.codicon-horizontal-rule:before { content: "\f177" }
.codicon-hubot:before { content: "\f178" }
.codicon-inbox:before { content: "\f179" }
.codicon-interface:before { content: "\f17a" }
.codicon-issue-closed:before { content: "\f17b" }
.codicon-issue-reopened:before { content: "\f17c" }
.codicon-issues:before { content: "\f17d" }
.codicon-italic:before { content: "\f17e" }
.codicon-jersey:before { content: "\f17f" }
.codicon-json:before { content: "\f180" }
.codicon-kebab-vertical:before { content: "\f181" }
.codicon-key:before { content: "\f182" }
.codicon-keyword:before { content: "\f183" }
.codicon-law:before { content: "\f184" }
.codicon-lightbulb-autofix:before { content: "\f185" }
.codicon-link-external:before { content: "\f186" }
.codicon-link:before { content: "\f187" }
.codicon-list-ordered:before { content: "\f188" }
.codicon-list-unordered:before { content: "\f189" }
.codicon-live-share:before { content: "\f18a" }
.codicon-loading:before { content: "\f18b" }
.codicon-location:before { content: "\f18c" }
.codicon-mail-read:before { content: "\f18d" }
.codicon-mail:before { content: "\f18e" }
.codicon-markdown:before { content: "\f18f" }
.codicon-megaphone:before { content: "\f190" }
.codicon-mention:before { content: "\f191" }
.codicon-method:before { content: "\f192" }
.codicon-milestone:before { content: "\f193" }
.codicon-misc:before { content: "\f194" }
.codicon-mortar-board:before { content: "\f195" }
.codicon-move:before { content: "\f196" }
.codicon-multiple-windows:before { content: "\f197" }
.codicon-mute:before { content: "\f198" }
.codicon-namespace:before { content: "\f199" }
.codicon-no-newline:before { content: "\f19a" }
.codicon-note:before { content: "\f19b" }
.codicon-numeric:before { content: "\f19c" }
.codicon-octoface:before { content: "\f19d" }
.codicon-open-preview:before { content: "\f19e" }
.codicon-operator:before { content: "\f19f" }
.codicon-package:before { content: "\f1a0" }
.codicon-paintcan:before { content: "\f1a1" }
.codicon-parameter:before { content: "\f1a2" }
.codicon-pause:before { content: "\f1a3" }
.codicon-pin:before { content: "\f1a4" }
.codicon-play:before { content: "\f1a5" }
.codicon-plug:before { content: "\f1a6" }
.codicon-preserve-case:before { content: "\f1a7" }
.codicon-preview:before { content: "\f1a8" }
.codicon-project:before { content: "\f1a9" }
.codicon-property:before { content: "\f1aa" }
.codicon-pulse:before { content: "\f1ab" }
.codicon-question:before { content: "\f1ac" }
.codicon-quote:before { content: "\f1ad" }
.codicon-radio-tower:before { content: "\f1ae" }
.codicon-reactions:before { content: "\f1af" }
.codicon-references:before { content: "\f1b0" }
.codicon-refresh:before { content: "\f1b1" }
.codicon-regex:before { content: "\f1b2" }
.codicon-remote:before { content: "\f1b3" }
.codicon-remove:before { content: "\f1b4" }
.codicon-replace-all:before { content: "\f1b5" }
.codicon-replace:before { content: "\f1b6" }
.codicon-repo-clone:before { content: "\f1b7" }
.codicon-repo-force-push:before { content: "\f1b8" }
.codicon-repo-pull:before { content: "\f1b9" }
.codicon-repo-push:before { content: "\f1ba" }
.codicon-report:before { content: "\f1bb" }
.codicon-request-changes:before { content: "\f1bc" }
.codicon-restart:before { content: "\f1bd" }
.codicon-rocket:before { content: "\f1be" }
.codicon-root-folder-opened:before { content: "\f1bf" }
.codicon-root-folder:before { content: "\f1c0" }
.codicon-rss:before { content: "\f1c1" }
.codicon-ruby:before { content: "\f1c2" }
.codicon-ruler:before { content: "\f1c3" }
.codicon-save-all:before { content: "\f1c4" }
.codicon-save-as:before { content: "\f1c5" }
.codicon-save:before { content: "\f1c6" }
.codicon-screen-full:before { content: "\f1c7" }
.codicon-screen-normal:before { content: "\f1c8" }
.codicon-search-stop:before { content: "\f1c9" }
.codicon-selection:before { content: "\f1ca" }
.codicon-server:before { content: "\f1cb" }
.codicon-settings:before { content: "\f1cc" }
.codicon-shield:before { content: "\f1cd" }
.codicon-smiley:before { content: "\f1ce" }
.codicon-snippet:before { content: "\f1cf" }
.codicon-sort-precedence:before { content: "\f1d0" }
.codicon-split-horizontal:before { content: "\f1d1" }
.codicon-split-vertical:before { content: "\f1d2" }
.codicon-squirrel:before { content: "\f1d3" }
.codicon-star-empty:before { content: "\f1d4" }
.codicon-star-full:before { content: "\f1d5" }
.codicon-star-half:before { content: "\f1d6" }
.codicon-start:before { content: "\f1d7" }
.codicon-step-into:before { content: "\f1d8" }
.codicon-step-out:before { content: "\f1d9" }
.codicon-step-over:before { content: "\f1da" }
.codicon-string:before { content: "\f1db" }
.codicon-structure:before { content: "\f1dc" }
.codicon-tasklist:before { content: "\f1dd" }
.codicon-telescope:before { content: "\f1de" }
.codicon-text-size:before { content: "\f1df" }
.codicon-three-bars:before { content: "\f1e0" }
.codicon-thumbsdown:before { content: "\f1e1" }
.codicon-thumbsup:before { content: "\f1e2" }
.codicon-tools:before { content: "\f1e3" }
.codicon-trash:before { content: "\f1e4" }
.codicon-triangle-down:before { content: "\f1e5" }
.codicon-triangle-left:before { content: "\f1e6" }
.codicon-triangle-right:before { content: "\f1e7" }
.codicon-triangle-up:before { content: "\f1e8" }
.codicon-twitter:before { content: "\f1e9" }
.codicon-unfold:before { content: "\f1ea" }
.codicon-unlock:before { content: "\f1eb" }
.codicon-unmute:before { content: "\f1ec" }
.codicon-unverified:before { content: "\f1ed" }
.codicon-variable:before { content: "\f1ee" }
.codicon-verified:before { content: "\f1ef" }
.codicon-versions:before { content: "\f1f0" }
.codicon-vm-active:before { content: "\f1f1" }
.codicon-vm-outline:before { content: "\f1f2" }
.codicon-vm-running:before { content: "\f1f3" }
.codicon-watch:before { content: "\f1f4" }
.codicon-whitespace:before { content: "\f1f5" }
.codicon-whole-word:before { content: "\f1f6" }
.codicon-window:before { content: "\f1f7" }
.codicon-word-wrap:before { content: "\f1f8" }
.codicon-zoom-in:before { content: "\f1f9" }
.codicon-zoom-out:before { content: "\f1fa" }
.codicon-trash:before { content: "\ea81" }
.codicon-trashcan:before { content: "\ea81" }
.codicon-history:before { content: "\ea82" }
.codicon-clock:before { content: "\ea82" }
.codicon-folder:before { content: "\ea83" }
.codicon-file-directory:before { content: "\ea83" }
.codicon-logo-github:before { content: "\ea84" }
.codicon-mark-github:before { content: "\ea84" }
.codicon-github:before { content: "\ea84" }
.codicon-terminal:before { content: "\ea85" }
.codicon-console:before { content: "\ea85" }
.codicon-zap:before { content: "\ea86" }
.codicon-event:before { content: "\ea86" }
.codicon-error:before { content: "\ea87" }
.codicon-stop:before { content: "\ea87" }
.codicon-activate-breakpoints:before { content: "\f101" }
.codicon-archive:before { content: "\f102" }
.codicon-array:before { content: "\f103" }
.codicon-arrow-both:before { content: "\f104" }
.codicon-arrow-down:before { content: "\f105" }
.codicon-arrow-left:before { content: "\f106" }
.codicon-arrow-right:before { content: "\f107" }
.codicon-arrow-small-down:before { content: "\f108" }
.codicon-arrow-small-left:before { content: "\f109" }
.codicon-arrow-small-right:before { content: "\f10a" }
.codicon-arrow-small-up:before { content: "\f10b" }
.codicon-arrow-up:before { content: "\f10c" }
.codicon-bell:before { content: "\f10d" }
.codicon-bold:before { content: "\f10e" }
.codicon-book:before { content: "\f10f" }
.codicon-bookmark:before { content: "\f110" }
.codicon-boolean:before { content: "\f111" }
.codicon-breakpoint-conditional-unverified:before { content: "\f112" }
.codicon-breakpoint-conditional:before { content: "\f113" }
.codicon-breakpoint-data-unverified:before { content: "\f114" }
.codicon-breakpoint-data:before { content: "\f115" }
.codicon-breakpoint-log-unverified:before { content: "\f116" }
.codicon-breakpoint-log:before { content: "\f117" }
.codicon-briefcase:before { content: "\f118" }
.codicon-broadcast:before { content: "\f119" }
.codicon-browser:before { content: "\f11a" }
.codicon-bug:before { content: "\f11b" }
.codicon-calendar:before { content: "\f11c" }
.codicon-case-sensitive:before { content: "\f11d" }
.codicon-check:before { content: "\f11e" }
.codicon-checklist:before { content: "\f11f" }
.codicon-chevron-down:before { content: "\f120" }
.codicon-chevron-left:before { content: "\f121" }
.codicon-chevron-right:before { content: "\f122" }
.codicon-chevron-up:before { content: "\f123" }
.codicon-chrome-close:before { content: "\f124" }
.codicon-chrome-maximize:before { content: "\f125" }
.codicon-chrome-minimize:before { content: "\f126" }
.codicon-chrome-restore:before { content: "\f127" }
.codicon-circle-outline:before { content: "\f128" }
.codicon-circle-slash:before { content: "\f129" }
.codicon-circuit-board:before { content: "\f12a" }
.codicon-class:before { content: "\f12b" }
.codicon-clear-all:before { content: "\f12c" }
.codicon-clippy:before { content: "\f12d" }
.codicon-close-all:before { content: "\f12e" }
.codicon-cloud-download:before { content: "\f12f" }
.codicon-cloud-upload:before { content: "\f130" }
.codicon-code:before { content: "\f131" }
.codicon-collapse-all:before { content: "\f132" }
.codicon-color-mode:before { content: "\f133" }
.codicon-color:before { content: "\f134" }
.codicon-comment-discussion:before { content: "\f135" }
.codicon-compare-changes:before { content: "\f136" }
.codicon-constant:before { content: "\f137" }
.codicon-continue:before { content: "\f138" }
.codicon-credit-card:before { content: "\f139" }
.codicon-current-and-breakpoint:before { content: "\f13a" }
.codicon-current:before { content: "\f13b" }
.codicon-dash:before { content: "\f13c" }
.codicon-dashboard:before { content: "\f13d" }
.codicon-database:before { content: "\f13e" }
.codicon-debug-disconnect:before { content: "\f13f" }
.codicon-debug-pause:before { content: "\f140" }
.codicon-debug-restart:before { content: "\f141" }
.codicon-debug-start:before { content: "\f142" }
.codicon-debug-step-into:before { content: "\f143" }
.codicon-debug-step-out:before { content: "\f144" }
.codicon-debug-step-over:before { content: "\f145" }
.codicon-debug-stop:before { content: "\f146" }
.codicon-debug:before { content: "\f147" }
.codicon-device-camera-video:before { content: "\f148" }
.codicon-device-camera:before { content: "\f149" }
.codicon-device-mobile:before { content: "\f14a" }
.codicon-diff-added:before { content: "\f14b" }
.codicon-diff-ignored:before { content: "\f14c" }
.codicon-diff-modified:before { content: "\f14d" }
.codicon-diff-removed:before { content: "\f14e" }
.codicon-diff-renamed:before { content: "\f14f" }
.codicon-diff:before { content: "\f150" }
.codicon-discard:before { content: "\f151" }
.codicon-editor-layout:before { content: "\f152" }
.codicon-ellipsis:before { content: "\f153" }
.codicon-empty-window:before { content: "\f154" }
.codicon-enumerator-member:before { content: "\f155" }
.codicon-enumerator:before { content: "\f156" }
.codicon-exclude:before { content: "\f157" }
.codicon-extensions:before { content: "\f158" }
.codicon-eye-closed:before { content: "\f159" }
.codicon-field:before { content: "\f15a" }
.codicon-file-binary:before { content: "\f15b" }
.codicon-file-code:before { content: "\f15c" }
.codicon-file-media:before { content: "\f15d" }
.codicon-file-pdf:before { content: "\f15e" }
.codicon-file-submodule:before { content: "\f15f" }
.codicon-file-symlink-directory:before { content: "\f160" }
.codicon-file-symlink-file:before { content: "\f161" }
.codicon-file-zip:before { content: "\f162" }
.codicon-files:before { content: "\f163" }
.codicon-filter:before { content: "\f164" }
.codicon-flame:before { content: "\f165" }
.codicon-fold-down:before { content: "\f166" }
.codicon-fold-up:before { content: "\f167" }
.codicon-fold:before { content: "\f168" }
.codicon-folder-active:before { content: "\f169" }
.codicon-folder-opened:before { content: "\f16a" }
.codicon-gear:before { content: "\f16b" }
.codicon-gift:before { content: "\f16c" }
.codicon-gist-secret:before { content: "\f16d" }
.codicon-gist:before { content: "\f16e" }
.codicon-git-commit:before { content: "\f16f" }
.codicon-git-compare:before { content: "\f170" }
.codicon-git-merge:before { content: "\f171" }
.codicon-github-action:before { content: "\f172" }
.codicon-github-alt:before { content: "\f173" }
.codicon-globe:before { content: "\f174" }
.codicon-go-to-file:before { content: "\f175" }
.codicon-grabber:before { content: "\f176" }
.codicon-graph:before { content: "\f177" }
.codicon-gripper:before { content: "\f178" }
.codicon-heart:before { content: "\f179" }
.codicon-home:before { content: "\f17a" }
.codicon-horizontal-rule:before { content: "\f17b" }
.codicon-hubot:before { content: "\f17c" }
.codicon-inbox:before { content: "\f17d" }
.codicon-interface:before { content: "\f17e" }
.codicon-issue-closed:before { content: "\f17f" }
.codicon-issue-reopened:before { content: "\f180" }
.codicon-issues:before { content: "\f181" }
.codicon-italic:before { content: "\f182" }
.codicon-jersey:before { content: "\f183" }
.codicon-json:before { content: "\f184" }
.codicon-kebab-vertical:before { content: "\f185" }
.codicon-key:before { content: "\f186" }
.codicon-keyword:before { content: "\f187" }
.codicon-law:before { content: "\f188" }
.codicon-lightbulb-autofix:before { content: "\f189" }
.codicon-link-external:before { content: "\f18a" }
.codicon-link:before { content: "\f18b" }
.codicon-list-ordered:before { content: "\f18c" }
.codicon-list-unordered:before { content: "\f18d" }
.codicon-live-share:before { content: "\f18e" }
.codicon-loading:before { content: "\f18f" }
.codicon-location:before { content: "\f190" }
.codicon-mail-read:before { content: "\f191" }
.codicon-mail:before { content: "\f192" }
.codicon-markdown:before { content: "\f193" }
.codicon-megaphone:before { content: "\f194" }
.codicon-mention:before { content: "\f195" }
.codicon-method:before { content: "\f196" }
.codicon-milestone:before { content: "\f197" }
.codicon-misc:before { content: "\f198" }
.codicon-mortar-board:before { content: "\f199" }
.codicon-move:before { content: "\f19a" }
.codicon-multiple-windows:before { content: "\f19b" }
.codicon-mute:before { content: "\f19c" }
.codicon-namespace:before { content: "\f19d" }
.codicon-no-newline:before { content: "\f19e" }
.codicon-note:before { content: "\f19f" }
.codicon-numeric:before { content: "\f1a0" }
.codicon-octoface:before { content: "\f1a1" }
.codicon-open-preview:before { content: "\f1a2" }
.codicon-operator:before { content: "\f1a3" }
.codicon-package:before { content: "\f1a4" }
.codicon-paintcan:before { content: "\f1a5" }
.codicon-parameter:before { content: "\f1a6" }
.codicon-pin:before { content: "\f1a7" }
.codicon-play:before { content: "\f1a8" }
.codicon-plug:before { content: "\f1a9" }
.codicon-preserve-case:before { content: "\f1aa" }
.codicon-preview:before { content: "\f1ab" }
.codicon-project:before { content: "\f1ac" }
.codicon-property:before { content: "\f1ad" }
.codicon-pulse:before { content: "\f1ae" }
.codicon-question:before { content: "\f1af" }
.codicon-quote:before { content: "\f1b0" }
.codicon-radio-tower:before { content: "\f1b1" }
.codicon-reactions:before { content: "\f1b2" }
.codicon-references:before { content: "\f1b3" }
.codicon-refresh:before { content: "\f1b4" }
.codicon-regex:before { content: "\f1b5" }
.codicon-remote:before { content: "\f1b6" }
.codicon-remove:before { content: "\f1b7" }
.codicon-replace-all:before { content: "\f1b8" }
.codicon-replace:before { content: "\f1b9" }
.codicon-repo-clone:before { content: "\f1ba" }
.codicon-repo-force-push:before { content: "\f1bb" }
.codicon-repo-pull:before { content: "\f1bc" }
.codicon-repo-push:before { content: "\f1bd" }
.codicon-report:before { content: "\f1be" }
.codicon-request-changes:before { content: "\f1bf" }
.codicon-rocket:before { content: "\f1c0" }
.codicon-root-folder-opened:before { content: "\f1c1" }
.codicon-root-folder:before { content: "\f1c2" }
.codicon-rss:before { content: "\f1c3" }
.codicon-ruby:before { content: "\f1c4" }
.codicon-ruler:before { content: "\f1c5" }
.codicon-save-all:before { content: "\f1c6" }
.codicon-save-as:before { content: "\f1c7" }
.codicon-save:before { content: "\f1c8" }
.codicon-screen-full:before { content: "\f1c9" }
.codicon-screen-normal:before { content: "\f1ca" }
.codicon-search-stop:before { content: "\f1cb" }
.codicon-selection:before { content: "\f1cc" }
.codicon-server:before { content: "\f1cd" }
.codicon-settings:before { content: "\f1ce" }
.codicon-shield:before { content: "\f1cf" }
.codicon-smiley:before { content: "\f1d0" }
.codicon-snippet:before { content: "\f1d1" }
.codicon-sort-precedence:before { content: "\f1d2" }
.codicon-split-horizontal:before { content: "\f1d3" }
.codicon-split-vertical:before { content: "\f1d4" }
.codicon-squirrel:before { content: "\f1d5" }
.codicon-star-full:before { content: "\f1d6" }
.codicon-star-half:before { content: "\f1d7" }
.codicon-string:before { content: "\f1d8" }
.codicon-structure:before { content: "\f1d9" }
.codicon-tasklist:before { content: "\f1da" }
.codicon-telescope:before { content: "\f1db" }
.codicon-text-size:before { content: "\f1dc" }
.codicon-three-bars:before { content: "\f1dd" }
.codicon-thumbsdown:before { content: "\f1de" }
.codicon-thumbsup:before { content: "\f1df" }
.codicon-tools:before { content: "\f1e0" }
.codicon-triangle-down:before { content: "\f1e1" }
.codicon-triangle-left:before { content: "\f1e2" }
.codicon-triangle-right:before { content: "\f1e3" }
.codicon-triangle-up:before { content: "\f1e4" }
.codicon-twitter:before { content: "\f1e5" }
.codicon-unfold:before { content: "\f1e6" }
.codicon-unlock:before { content: "\f1e7" }
.codicon-unmute:before { content: "\f1e8" }
.codicon-unverified:before { content: "\f1e9" }
.codicon-variable:before { content: "\f1ea" }
.codicon-verified:before { content: "\f1eb" }
.codicon-versions:before { content: "\f1ec" }
.codicon-vm-active:before { content: "\f1ed" }
.codicon-vm-outline:before { content: "\f1ee" }
.codicon-vm-running:before { content: "\f1ef" }
.codicon-watch:before { content: "\f1f0" }
.codicon-whitespace:before { content: "\f1f1" }
.codicon-whole-word:before { content: "\f1f2" }
.codicon-window:before { content: "\f1f3" }
.codicon-word-wrap:before { content: "\f1f4" }
.codicon-zoom-in:before { content: "\f1f5" }
.codicon-zoom-out:before { content: "\f1f6" }
@@ -8,7 +8,7 @@ import 'vs/css!./codicon/codicon-animations';
import { escape } from 'vs/base/common/strings';
function expand(text: string): string {
return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => {
return text.replace(/\$\((([a-z0-9\-]+?)(~([a-z0-9\-]*?))?)\)/gi, (_match, _g1, name, _g3, animation) => {
return `<span class="codicon codicon-${name} ${animation ? `codicon-animation-${animation}` : ''}"></span>`;
});
}
@@ -263,7 +263,7 @@ export class ContextView extends Disposable {
const delegate = this.delegate;
this.delegate = null;
if (delegate && delegate.onHide) {
if (delegate?.onHide) {
delegate.onHide(data);
}
@@ -85,15 +85,15 @@ export class CountBadge {
private applyStyles(): void {
if (this.element) {
const background = this.badgeBackground ? this.badgeBackground.toString() : null;
const foreground = this.badgeForeground ? this.badgeForeground.toString() : null;
const border = this.badgeBorder ? this.badgeBorder.toString() : null;
const background = this.badgeBackground ? this.badgeBackground.toString() : '';
const foreground = this.badgeForeground ? this.badgeForeground.toString() : '';
const border = this.badgeBorder ? this.badgeBorder.toString() : '';
this.element.style.backgroundColor = background;
this.element.style.color = foreground;
this.element.style.borderWidth = border ? '1px' : null;
this.element.style.borderStyle = border ? 'solid' : null;
this.element.style.borderWidth = border ? '1px' : '';
this.element.style.borderStyle = border ? 'solid' : '';
this.element.style.borderColor = border;
}
}
+10 -6
View File
@@ -142,7 +142,9 @@ export class Dialog extends Disposable {
let eventHandled = false;
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
if (!this.checkboxHasFocus && focusedButton === 0) {
this.checkbox!.domNode.focus();
if (this.checkbox) {
this.checkbox.domNode.focus();
}
this.checkboxHasFocus = true;
} else {
focusedButton = (this.checkboxHasFocus ? 0 : focusedButton) + buttonGroup.buttons.length - 1;
@@ -154,7 +156,9 @@ export class Dialog extends Disposable {
eventHandled = true;
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
if (!this.checkboxHasFocus && focusedButton === buttonGroup.buttons.length - 1) {
this.checkbox!.domNode.focus();
if (this.checkbox) {
this.checkbox.domNode.focus();
}
this.checkboxHasFocus = true;
} else {
focusedButton = this.checkboxHasFocus ? 0 : focusedButton + 1;
@@ -237,10 +241,10 @@ export class Dialog extends Disposable {
if (this.styles) {
const style = this.styles;
const fgColor = style.dialogForeground ? `${style.dialogForeground}` : null;
const bgColor = style.dialogBackground ? `${style.dialogBackground}` : null;
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : null;
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : null;
const fgColor = style.dialogForeground ? `${style.dialogForeground}` : '';
const bgColor = style.dialogBackground ? `${style.dialogBackground}` : '';
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
if (this.element) {
this.element.style.color = fgColor;
+10 -6
View File
@@ -208,8 +208,8 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions {
export class DropdownMenu extends BaseDropdown {
private _contextMenuProvider: IContextMenuProvider;
private _menuOptions: IMenuOptions;
private _actions: ReadonlyArray<IAction>;
private _menuOptions: IMenuOptions | undefined;
private _actions: ReadonlyArray<IAction> = [];
private actionProvider?: IActionProvider;
private menuClassName: string;
@@ -222,11 +222,11 @@ export class DropdownMenu extends BaseDropdown {
this.menuClassName = options.menuClassName || '';
}
set menuOptions(options: IMenuOptions) {
set menuOptions(options: IMenuOptions | undefined) {
this._menuOptions = options;
}
get menuOptions(): IMenuOptions {
get menuOptions(): IMenuOptions | undefined {
return this._menuOptions;
}
@@ -256,7 +256,7 @@ export class DropdownMenu extends BaseDropdown {
getMenuClassName: () => this.menuClassName,
onHide: () => this.onHide(),
actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,
anchorAlignment: this.menuOptions.anchorAlignment
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT
});
}
@@ -345,7 +345,11 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
super.setActionContext(newContext);
if (this.dropdownMenu) {
this.dropdownMenu.menuOptions.context = newContext;
if (this.dropdownMenu.menuOptions) {
this.dropdownMenu.menuOptions.context = newContext;
} else {
this.dropdownMenu.menuOptions = { context: newContext };
}
}
}
@@ -123,11 +123,96 @@ export class ReplaceInput extends Widget {
this.inputValidationErrorBackground = options.inputValidationErrorBackground;
this.inputValidationErrorForeground = options.inputValidationErrorForeground;
const history = options.history || [];
const flexibleHeight = !!options.flexibleHeight;
const flexibleWidth = !!options.flexibleWidth;
const flexibleMaxHeight = options.flexibleMaxHeight;
this.buildDomNode(options.history || [], flexibleHeight, flexibleWidth, flexibleMaxHeight);
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
ariaLabel: this.label || '',
placeholder: this.placeholder || '',
validationOptions: {
validation: this.validation
},
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight,
flexibleWidth,
flexibleMaxHeight
}));
this.preserveCase = this._register(new PreserveCaseCheckbox({
appendTitle: '',
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground,
}));
this._register(this.preserveCase.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.preserveCase.onKeyDown(e => {
this._onPreserveCaseKeyDown.fire(e);
}));
if (this._showOptionButtons) {
this.cachedOptionsWidth = this.preserveCase.width();
} else {
this.cachedOptionsWidth = 0;
}
// Arrow-Key support to navigate between options
let indexes = [this.preserveCase.domNode];
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
let index = indexes.indexOf(<HTMLElement>document.activeElement);
if (index >= 0) {
let newIndex: number = -1;
if (event.equals(KeyCode.RightArrow)) {
newIndex = (index + 1) % indexes.length;
} else if (event.equals(KeyCode.LeftArrow)) {
if (index === 0) {
newIndex = indexes.length - 1;
} else {
newIndex = index - 1;
}
}
if (event.equals(KeyCode.Escape)) {
indexes[index].blur();
} else if (newIndex >= 0) {
indexes[newIndex].focus();
}
dom.EventHelper.stop(event, true);
}
}
});
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.preserveCase.domNode);
this.domNode.appendChild(controls);
if (parent) {
parent.appendChild(this.domNode);
@@ -256,94 +341,6 @@ export class ReplaceInput extends Widget {
dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
}
private buildDomNode(history: string[], flexibleHeight: boolean, flexibleWidth: boolean, flexibleMaxHeight: number | undefined): void {
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
ariaLabel: this.label || '',
placeholder: this.placeholder || '',
validationOptions: {
validation: this.validation
},
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight,
flexibleWidth,
flexibleMaxHeight
}));
this.preserveCase = this._register(new PreserveCaseCheckbox({
appendTitle: '',
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder,
inputActiveOptionBackground: this.inputActiveOptionBackground,
}));
this._register(this.preserveCase.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.preserveCase.onKeyDown(e => {
this._onPreserveCaseKeyDown.fire(e);
}));
if (this._showOptionButtons) {
this.cachedOptionsWidth = this.preserveCase.width();
} else {
this.cachedOptionsWidth = 0;
}
// Arrow-Key support to navigate between options
let indexes = [this.preserveCase.domNode];
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
let index = indexes.indexOf(<HTMLElement>document.activeElement);
if (index >= 0) {
let newIndex: number = -1;
if (event.equals(KeyCode.RightArrow)) {
newIndex = (index + 1) % indexes.length;
} else if (event.equals(KeyCode.LeftArrow)) {
if (index === 0) {
newIndex = indexes.length - 1;
} else {
newIndex = index - 1;
}
}
if (event.equals(KeyCode.Escape)) {
indexes[index].blur();
} else if (newIndex >= 0) {
indexes[newIndex].focus();
}
dom.EventHelper.stop(event, true);
}
}
});
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.preserveCase.domNode);
this.domNode.appendChild(controls);
}
public validate(): void {
if (this.inputBox) {
this.inputBox.validate();
-1
View File
@@ -9,7 +9,6 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { tail2 as tail, equals } from 'vs/base/common/arrays';
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions } from './gridview';
import { Event } from 'vs/base/common/event';
import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview';
export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview';
@@ -15,15 +15,15 @@ export interface IHighlight {
export class HighlightedLabel {
private domNode: HTMLElement;
private text: string;
private title: string;
private highlights: IHighlight[];
private didEverRender: boolean;
private text: string = '';
private title: string = '';
private highlights: IHighlight[] = [];
private didEverRender: boolean = false;
constructor(container: HTMLElement, private supportOcticons: boolean) {
constructor(container: HTMLElement, private supportCodicons: boolean) {
this.domNode = document.createElement('span');
this.domNode.className = 'monaco-highlighted-label';
this.didEverRender = false;
container.appendChild(this.domNode);
}
@@ -65,13 +65,13 @@ export class HighlightedLabel {
if (pos < highlight.start) {
htmlContent += '<span>';
const substring = this.text.substring(pos, highlight.start);
htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring);
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
htmlContent += '</span>';
pos = highlight.end;
}
htmlContent += '<span class="highlight">';
const substring = this.text.substring(highlight.start, highlight.end);
htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring);
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
htmlContent += '</span>';
pos = highlight.end;
}
@@ -79,7 +79,7 @@ export class HighlightedLabel {
if (pos < this.text.length) {
htmlContent += '<span>';
const substring = this.text.substring(pos);
htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring);
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
htmlContent += '</span>';
}
+10 -10
View File
@@ -12,7 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
export interface IIconLabelCreationOptions {
supportHighlights?: boolean;
supportDescriptionHighlights?: boolean;
supportOcticons?: boolean;
supportCodicons?: boolean;
}
export interface IIconLabelValueOptions {
@@ -77,7 +77,7 @@ class FastLabelNode {
}
this._empty = empty;
this._element.style.marginLeft = empty ? '0' : null;
this._element.style.marginLeft = empty ? '0' : '';
}
dispose(): void {
@@ -99,14 +99,14 @@ export class IconLabel extends Disposable {
this.labelDescriptionContainer = this._register(new FastLabelNode(dom.append(this.domNode.element, dom.$('.monaco-icon-label-description-container'))));
if (options && options.supportHighlights) {
this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !!options.supportOcticons);
if (options?.supportHighlights) {
this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !!options.supportCodicons);
} else {
this.labelNode = this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name'))));
}
if (options && options.supportDescriptionHighlights) {
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !!options.supportOcticons);
if (options?.supportDescriptionHighlights) {
this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !!options.supportCodicons);
} else {
this.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description'))));
}
@@ -129,10 +129,10 @@ export class IconLabel extends Disposable {
}
this.domNode.className = classes.join(' ');
this.domNode.title = options && options.title ? options.title : '';
this.domNode.title = options?.title || '';
if (this.labelNode instanceof HighlightedLabel) {
this.labelNode.set(label || '', options ? options.matches : undefined, options && options.title ? options.title : undefined, options && options.labelEscapeNewLines);
this.labelNode.set(label || '', options?.matches, options?.title, options?.labelEscapeNewLines);
} else {
this.labelNode.textContent = label || '';
}
@@ -144,14 +144,14 @@ export class IconLabel extends Disposable {
if (this.descriptionNode instanceof HighlightedLabel) {
this.descriptionNode.set(description || '', options ? options.descriptionMatches : undefined);
if (options && options.descriptionTitle) {
if (options?.descriptionTitle) {
this.descriptionNode.element.title = options.descriptionTitle;
} else {
this.descriptionNode.element.removeAttribute('title');
}
} else {
this.descriptionNode.textContent = description || '';
this.descriptionNode.title = options && options.descriptionTitle ? options.descriptionTitle : '';
this.descriptionNode.title = options?.descriptionTitle || '';
this.descriptionNode.empty = !description;
}
}
@@ -55,7 +55,7 @@
opacity: 0.75;
font-size: 90%;
font-weight: 600;
padding: 0 12px 0 5px;
padding: 0 16px 0 5px;
margin-left: auto;
text-align: center;
}
@@ -74,4 +74,4 @@
.monaco-list-row.focused.selected .label-description,
.monaco-list-row.selected .label-description {
opacity: .8;
}
}
+12 -12
View File
@@ -201,7 +201,7 @@ export class InputBox extends Widget {
const onSelectionChange = Event.filter(domEvent(document, 'selectionchange'), () => {
const selection = document.getSelection();
return !!selection && selection.anchorNode === wrapper;
return selection?.anchorNode === wrapper;
});
// from DOM to ScrollableElement
@@ -375,7 +375,7 @@ export class InputBox extends Widget {
}
private updateScrollDimensions(): void {
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number' || !this.scrollableElement) {
return;
}
@@ -383,8 +383,8 @@ export class InputBox extends Widget {
const height = this.cachedHeight;
const scrollTop = this.input.scrollTop;
this.scrollableElement!.setScrollDimensions({ scrollHeight, height });
this.scrollableElement!.setScrollPosition({ scrollTop });
this.scrollableElement.setScrollDimensions({ scrollHeight, height });
this.scrollableElement.setScrollPosition({ scrollTop });
}
public showMessage(message: IMessage, force?: boolean): void {
@@ -397,7 +397,7 @@ export class InputBox extends Widget {
dom.addClass(this.element, this.classForType(message.type));
const styles = this.stylesForType(this.message.type);
this.element.style.border = styles.border ? `1px solid ${styles.border}` : null;
this.element.style.border = styles.border ? `1px solid ${styles.border}` : '';
// ARIA Support
let alertText: string;
@@ -507,9 +507,9 @@ export class InputBox extends Widget {
dom.addClass(spanElement, this.classForType(this.message.type));
const styles = this.stylesForType(this.message.type);
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : null;
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
spanElement.style.color = styles.foreground ? styles.foreground.toString() : null;
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : null;
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
dom.append(div, spanElement);
@@ -586,17 +586,17 @@ export class InputBox extends Widget {
}
protected applyStyles(): void {
const background = this.inputBackground ? this.inputBackground.toString() : null;
const foreground = this.inputForeground ? this.inputForeground.toString() : null;
const border = this.inputBorder ? this.inputBorder.toString() : null;
const background = this.inputBackground ? this.inputBackground.toString() : '';
const foreground = this.inputForeground ? this.inputForeground.toString() : '';
const border = this.inputBorder ? this.inputBorder.toString() : '';
this.element.style.backgroundColor = background;
this.element.style.color = foreground;
this.input.style.backgroundColor = background;
this.input.style.color = foreground;
this.element.style.borderWidth = border ? '1px' : null;
this.element.style.borderStyle = border ? 'solid' : null;
this.element.style.borderWidth = border ? '1px' : '';
this.element.style.borderStyle = border ? 'solid' : '';
this.element.style.borderColor = border;
}
@@ -80,20 +80,20 @@ export class KeybindingLabel {
private renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches | null) {
const modifierLabels = UILabelProvider.modifierLabels[this.os];
if (part.ctrlKey) {
this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match && match.ctrlKey), modifierLabels.separator);
this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match?.ctrlKey), modifierLabels.separator);
}
if (part.shiftKey) {
this.renderKey(parent, modifierLabels.shiftKey, Boolean(match && match.shiftKey), modifierLabels.separator);
this.renderKey(parent, modifierLabels.shiftKey, Boolean(match?.shiftKey), modifierLabels.separator);
}
if (part.altKey) {
this.renderKey(parent, modifierLabels.altKey, Boolean(match && match.altKey), modifierLabels.separator);
this.renderKey(parent, modifierLabels.altKey, Boolean(match?.altKey), modifierLabels.separator);
}
if (part.metaKey) {
this.renderKey(parent, modifierLabels.metaKey, Boolean(match && match.metaKey), modifierLabels.separator);
this.renderKey(parent, modifierLabels.metaKey, Boolean(match?.metaKey), modifierLabels.separator);
}
const keyLabel = part.keyLabel;
if (keyLabel) {
this.renderKey(parent, keyLabel, Boolean(match && match.keyCode), '');
this.renderKey(parent, keyLabel, Boolean(match?.keyCode), '');
}
}
+16
View File
@@ -115,3 +115,19 @@ export class ListError extends Error {
super(`ListError [${user}] ${message}`);
}
}
export abstract class CachedListVirtualDelegate<T extends object> implements IListVirtualDelegate<T> {
private cache = new WeakMap<T, number>();
getHeight(element: T): number {
return this.cache.get(element) ?? this.estimateHeight(element);
}
protected abstract estimateHeight(element: T): number;
abstract getTemplateId(element: T): string;
setDynamicHeight(element: T, height: number): void {
this.cache.set(element, height);
}
}
@@ -155,6 +155,14 @@ export class PagedList<T> implements IDisposable {
this.list.scrollTop = scrollTop;
}
get scrollLeft(): number {
return this.list.scrollLeft;
}
set scrollLeft(scrollLeft: number) {
this.list.scrollLeft = scrollLeft;
}
open(indexes: number[], browserEvent?: UIEvent): void {
this.list.open(indexes, browserEvent);
}
+4 -26
View File
@@ -14,8 +14,6 @@ import { ScrollEvent, ScrollbarVisibility, INewScrollDimensions } from 'vs/base/
import { RangeMap, shift } from './rangeMap';
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListDragEvent, IListDragAndDrop, ListDragOverEffect } from './list';
import { RowCache, IRow } from './rowCache';
import { isWindows } from 'vs/base/common/platform';
import * as browser from 'vs/base/browser/browser';
import { ISpliceable } from 'vs/base/common/sequence';
import { memoize } from 'vs/base/common/decorators';
import { Range, IRange } from 'vs/base/common/range';
@@ -179,7 +177,6 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private additionalScrollHeight: number;
private ariaProvider: IAriaProvider<T>;
private scrollWidth: number | undefined;
private canUseTranslate3d: boolean | undefined = undefined;
private dnd: IListViewDragAndDrop<T>;
private canDrop: boolean = false;
@@ -236,6 +233,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.rowsContainer = document.createElement('div');
this.rowsContainer.className = 'monaco-list-rows';
this.rowsContainer.style.willChange = 'transform';
this.disposables.add(Gesture.addTarget(this.rowsContainer));
this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, {
@@ -531,33 +529,13 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
}
}
const canUseTranslate3d = !isWindows && !browser.isFirefox && browser.getZoomLevel() === 0;
if (canUseTranslate3d) {
const transform = `translate3d(-${renderLeft}px, -${renderTop}px, 0px)`;
this.rowsContainer.style.transform = transform;
this.rowsContainer.style.webkitTransform = transform;
if (canUseTranslate3d !== this.canUseTranslate3d) {
this.rowsContainer.style.left = '0';
this.rowsContainer.style.top = '0';
}
} else {
this.rowsContainer.style.left = `-${renderLeft}px`;
this.rowsContainer.style.top = `-${renderTop}px`;
if (canUseTranslate3d !== this.canUseTranslate3d) {
this.rowsContainer.style.transform = '';
this.rowsContainer.style.webkitTransform = '';
}
}
this.rowsContainer.style.left = `-${renderLeft}px`;
this.rowsContainer.style.top = `-${renderTop}px`;
if (this.horizontalScrolling) {
this.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`;
}
this.canUseTranslate3d = canUseTranslate3d;
this.lastRenderTop = renderTop;
this.lastRenderHeight = renderHeight;
}
@@ -686,7 +664,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
return scrollPosition.scrollLeft;
}
setScrollLeftt(scrollLeft: number): void {
setScrollLeft(scrollLeft: number): void {
if (this.scrollableElementUpdateDisposable) {
this.scrollableElementUpdateDisposable.dispose();
this.scrollableElementUpdateDisposable = null;
+16 -9
View File
@@ -822,7 +822,7 @@ export interface IListOptions<T> extends IListStyles {
readonly automaticKeyboardNavigation?: boolean;
readonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider<T>;
readonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate;
readonly ariaRole?: ListAriaRootRole;
readonly ariaRole?: ListAriaRootRole | string;
readonly ariaLabel?: string;
readonly keyboardSupport?: boolean;
readonly multipleSelectionSupport?: boolean;
@@ -1198,11 +1198,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this.view = new ListView(container, virtualDelegate, renderers, viewOptions);
if (typeof _options.ariaRole !== 'string') {
this.view.domNode.setAttribute('role', ListAriaRootRole.TREE);
} else {
this.view.domNode.setAttribute('role', _options.ariaRole);
}
this.updateAriaRole();
this.styleElement = DOM.createStyleSheet(this.view.domNode);
@@ -1316,7 +1312,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
}
set scrollLeft(scrollLeft: number) {
this.view.setScrollLeftt(scrollLeft);
this.view.setScrollLeft(scrollLeft);
}
get scrollHeight(): number {
@@ -1537,7 +1533,9 @@ export class List<T> implements ISpliceable<T>, IDisposable {
const viewItemBottom = elementTop + elementHeight;
const wrapperBottom = scrollTop + this.view.renderHeight;
if (elementTop < scrollTop) {
if (elementTop < scrollTop && viewItemBottom >= wrapperBottom) {
// The element is already overflowing the viewport, no-op
} else if (elementTop < scrollTop) {
this.view.setScrollTop(elementTop);
} else if (viewItemBottom >= wrapperBottom) {
this.view.setScrollTop(viewItemBottom - this.view.renderHeight);
@@ -1612,10 +1610,19 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this.view.domNode.removeAttribute('aria-activedescendant');
}
this.view.domNode.setAttribute('role', 'tree');
this.updateAriaRole();
DOM.toggleClass(this.view.domNode, 'element-focused', focus.length > 0);
}
private updateAriaRole(): void {
if (typeof this.options.ariaRole !== 'string') {
this.view.domNode.setAttribute('role', ListAriaRootRole.TREE);
} else {
this.view.domNode.setAttribute('role', this.options.ariaRole);
}
}
private _onSelectionChange(): void {
const selection = this.selection.get();
+2 -1
View File
@@ -157,7 +157,7 @@
flex-wrap: wrap;
}
.fullscreen .menubar {
.fullscreen .menubar:not(.compact) {
margin: 0px;
padding: 0px 5px;
}
@@ -176,6 +176,7 @@
.menubar.compact > .menubar-menu-button {
width: 100%;
height: 100%;
padding: 0px;
}
.menubar .menubar-menu-items-holder {
+110 -73
View File
@@ -16,7 +16,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
import { Event, Emitter } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
@@ -66,9 +66,6 @@ export class Menu extends ActionBar {
private readonly menuDisposables: DisposableStore;
private scrollableElement: DomScrollableElement;
private menuElement: HTMLElement;
private scrollTopHold: number | undefined;
private readonly _onScroll: Emitter<void>;
constructor(container: HTMLElement, actions: ReadonlyArray<IAction>, options: IMenuOptions = {}) {
addClass(container, 'monaco-menu-container');
@@ -88,8 +85,6 @@ export class Menu extends ActionBar {
this.menuElement = menuElement;
this._onScroll = this._register(new Emitter<void>());
this.actionsList.setAttribute('role', 'menu');
this.actionsList.tabIndex = 0;
@@ -113,7 +108,7 @@ export class Menu extends ActionBar {
const actions = this.mnemonics.get(key)!;
if (actions.length === 1) {
if (actions[0] instanceof SubmenuMenuActionViewItem) {
if (actions[0] instanceof SubmenuMenuActionViewItem && actions[0].container) {
this.focusItemByElement(actions[0].container);
}
@@ -122,7 +117,7 @@ export class Menu extends ActionBar {
if (actions.length > 1) {
const action = actions.shift();
if (action) {
if (action && action.container) {
this.focusItemByElement(action.container);
actions.push(action);
}
@@ -153,17 +148,11 @@ export class Menu extends ActionBar {
let relatedTarget = e.relatedTarget as HTMLElement;
if (!isAncestor(relatedTarget, this.domNode)) {
this.focusedItem = undefined;
this.scrollTopHold = this.menuElement.scrollTop;
this.updateFocus();
e.stopPropagation();
}
}));
this._register(addDisposableListener(this.domNode, EventType.MOUSE_UP, e => {
// Absorb clicks in menu dead space https://github.com/Microsoft/vscode/issues/63575
EventHelper.stop(e, true);
}));
this._register(addDisposableListener(this.actionsList, EventType.MOUSE_OVER, e => {
let target = e.target as HTMLElement;
if (!target || !isAncestor(target, this.actionsList) || target === this.actionsList) {
@@ -176,7 +165,6 @@ export class Menu extends ActionBar {
if (hasClass(target, 'action-item')) {
const lastFocusedItem = this.focusedItem;
this.scrollTopHold = this.menuElement.scrollTop;
this.setFocusedItem(target);
if (lastFocusedItem !== this.focusedItem) {
@@ -191,8 +179,6 @@ export class Menu extends ActionBar {
this.mnemonics = new Map<string, Array<BaseMenuActionViewItem>>();
this.push(actions, { icon: true, label: true, isMenu: true });
// Scroll Logic
this.scrollableElement = this._register(new DomScrollableElement(menuElement, {
alwaysConsumeMouseWheel: true,
@@ -204,21 +190,17 @@ export class Menu extends ActionBar {
}));
const scrollElement = this.scrollableElement.getDomNode();
scrollElement.style.position = null;
scrollElement.style.position = '';
this._register(addDisposableListener(scrollElement, EventType.MOUSE_UP, e => {
// Absorb clicks in menu dead space https://github.com/Microsoft/vscode/issues/63575
// We do this on the scroll element so the scroll bar doesn't dismiss the menu either
e.preventDefault();
}));
menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 30)}px`;
this.menuDisposables.add(this.scrollableElement.onScroll(() => {
this._onScroll.fire();
}, this));
this._register(addDisposableListener(this.menuElement, EventType.SCROLL, (e: ScrollEvent) => {
if (this.scrollTopHold !== undefined) {
this.menuElement.scrollTop = this.scrollTopHold;
this.scrollTopHold = undefined;
}
this.scrollableElement.scanDomNode();
}));
this.push(actions, { icon: true, label: true, isMenu: true });
container.appendChild(this.scrollableElement.getDomNode());
this.scrollableElement.scanDomNode();
@@ -231,10 +213,10 @@ export class Menu extends ActionBar {
style(style: IMenuStyles): void {
const container = this.getContainer();
const fgColor = style.foregroundColor ? `${style.foregroundColor}` : null;
const bgColor = style.backgroundColor ? `${style.backgroundColor}` : null;
const border = style.borderColor ? `2px solid ${style.borderColor}` : null;
const shadow = style.shadowColor ? `0 2px 4px ${style.shadowColor}` : null;
const fgColor = style.foregroundColor ? `${style.foregroundColor}` : '';
const bgColor = style.backgroundColor ? `${style.backgroundColor}` : '';
const border = style.borderColor ? `2px solid ${style.borderColor}` : '';
const shadow = style.shadowColor ? `0 2px 4px ${style.shadowColor}` : '';
container.style.border = border;
this.domNode.style.color = fgColor;
@@ -254,8 +236,8 @@ export class Menu extends ActionBar {
return this.scrollableElement.getDomNode();
}
get onScroll(): Event<void> {
return this._onScroll.event;
get onScroll(): Event<ScrollEvent> {
return this.scrollableElement.onScroll;
}
get scrollOffset(): number {
@@ -295,6 +277,19 @@ export class Menu extends ActionBar {
}
}
protected updateFocus(fromRight?: boolean): void {
super.updateFocus(fromRight, true);
if (typeof this.focusedItem !== 'undefined') {
// Workaround for #80047 caused by an issue in chromium
// https://bugs.chromium.org/p/chromium/issues/detail?id=414283
// When that's fixed, just call this.scrollableElement.scanDomNode()
this.scrollableElement.setScrollPosition({
scrollTop: Math.round(this.menuElement.scrollTop)
});
}
}
private doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem {
if (action instanceof Separator) {
return new MenuSeparatorActionViewItem(options.context, action, { icon: true });
@@ -356,17 +351,17 @@ interface IMenuItemOptions extends IActionViewItemOptions {
class BaseMenuActionViewItem extends BaseActionViewItem {
public container: HTMLElement;
public container: HTMLElement | undefined;
protected options: IMenuItemOptions;
protected item: HTMLElement;
protected item: HTMLElement | undefined;
private runOnceToEnableMouseUp: RunOnceScheduler;
private label: HTMLElement;
private check: HTMLElement;
private mnemonic: string;
private label: HTMLElement | undefined;
private check: HTMLElement | undefined;
private mnemonic: string | undefined;
private cssClass: string;
protected menuStyle: IMenuStyles;
protected menuStyle: IMenuStyles | undefined;
constructor(ctx: any, action: IAction, options: IMenuItemOptions = {}) {
options.isMenu = true;
@@ -395,6 +390,10 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {
if (e.defaultPrevented) {
return;
}
EventHelper.stop(e, true);
this.onClick(e);
}));
@@ -449,13 +448,19 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
focus(): void {
super.focus();
this.item.focus();
if (this.item) {
this.item.focus();
}
this.applyStyle();
}
updatePositionInSet(pos: number, setSize: number): void {
this.item.setAttribute('aria-posinset', `${pos}`);
this.item.setAttribute('aria-setsize', `${setSize}`);
if (this.item) {
this.item.setAttribute('aria-posinset', `${pos}`);
this.item.setAttribute('aria-setsize', `${setSize}`);
}
}
updateLabel(): void {
@@ -467,7 +472,9 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
label = cleanLabel;
}
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
if (this.label) {
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
}
const matches = MENU_MNEMONIC_REGEX.exec(label);
@@ -488,13 +495,17 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
label = label.replace(/&amp;&amp;/g, '&amp;');
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
if (this.item) {
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
}
} else {
label = label.replace(/&&/g, '&');
}
}
this.label.innerHTML = label.trim();
if (this.label) {
this.label.innerHTML = label.trim();
}
}
}
@@ -512,23 +523,23 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
}
if (title) {
if (title && this.item) {
this.item.title = title;
}
}
updateClass(): void {
if (this.cssClass) {
if (this.cssClass && this.item) {
removeClasses(this.item, this.cssClass);
}
if (this.options.icon) {
if (this.options.icon && this.label) {
this.cssClass = this.getAction().class || '';
addClass(this.label, 'icon');
if (this.cssClass) {
addClasses(this.label, this.cssClass);
}
this.updateEnabled();
} else {
} else if (this.label) {
removeClass(this.label, 'icon');
}
}
@@ -539,19 +550,27 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
removeClass(this.element, 'disabled');
}
removeClass(this.item, 'disabled');
this.item.tabIndex = 0;
if (this.item) {
removeClass(this.item, 'disabled');
this.item.tabIndex = 0;
}
} else {
if (this.element) {
addClass(this.element, 'disabled');
}
addClass(this.item, 'disabled');
removeTabIndexAndUpdateFocus(this.item);
if (this.item) {
addClass(this.item, 'disabled');
removeTabIndexAndUpdateFocus(this.item);
}
}
}
updateChecked(): void {
if (!this.item) {
return;
}
if (this.getAction().checked) {
addClass(this.item, 'checked');
this.item.setAttribute('role', 'menuitemcheckbox');
@@ -563,7 +582,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
}
getMnemonic(): string {
getMnemonic(): string | undefined {
return this.mnemonic;
}
@@ -575,12 +594,20 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
const isSelected = this.element && hasClass(this.element, 'focused');
const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;
const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : this.menuStyle.backgroundColor;
const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : null;
const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : '';
this.item.style.color = fgColor ? `${fgColor}` : null;
this.check.style.backgroundColor = fgColor ? `${fgColor}` : null;
this.item.style.backgroundColor = bgColor ? `${bgColor}` : null;
this.container.style.border = border;
if (this.item) {
this.item.style.color = fgColor ? `${fgColor}` : null;
this.item.style.backgroundColor = bgColor ? `${bgColor}` : '';
}
if (this.check) {
this.check.style.backgroundColor = fgColor ? `${fgColor}` : '';
}
if (this.container) {
this.container.style.border = border;
}
}
style(style: IMenuStyles): void {
@@ -590,11 +617,11 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
private mysubmenu: Menu | null;
private mysubmenu: Menu | null = null;
private submenuContainer: HTMLElement | undefined;
private submenuIndicator: HTMLElement;
private submenuIndicator: HTMLElement | undefined;
private readonly submenuDisposables = this._register(new DisposableStore());
private mouseOver: boolean;
private mouseOver: boolean = false;
private showScheduler: RunOnceScheduler;
private hideScheduler: RunOnceScheduler;
private expandDirection: Direction;
@@ -631,11 +658,13 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
return;
}
addClass(this.item, 'monaco-submenu-item');
this.item.setAttribute('aria-haspopup', 'true');
if (this.item) {
addClass(this.item, 'monaco-submenu-item');
this.item.setAttribute('aria-haspopup', 'true');
this.submenuIndicator = append(this.item, $('span.submenu-indicator'));
this.submenuIndicator.setAttribute('aria-hidden', 'true');
this.submenuIndicator = append(this.item, $('span.submenu-indicator'));
this.submenuIndicator.setAttribute('aria-hidden', 'true');
}
this._register(addDisposableListener(this.element, EventType.KEY_UP, e => {
let event = new StandardKeyboardEvent(e);
@@ -690,7 +719,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
EventHelper.stop(e, true);
this.cleanupExistingSubmenu(false);
this.createSubmenu(false);
this.createSubmenu(true);
}
private cleanupExistingSubmenu(force: boolean): void {
@@ -714,6 +743,12 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
this.submenuContainer = append(this.element, $('div.monaco-submenu'));
addClasses(this.submenuContainer, 'menubar-menu-items-holder', 'context-view');
// Set the top value of the menu container before construction
// This allows the menu constructor to calculate the proper max height
const computedStyles = getComputedStyle(this.parentData.parent.domNode);
const paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0;
this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`;
this.parentData.submenu = new Menu(this.submenuContainer, this.submenuActions, this.submenuOptions);
if (this.menuStyle) {
this.parentData.submenu.style(this.menuStyle);
@@ -721,8 +756,6 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
const boundingRect = this.element.getBoundingClientRect();
const childBoundingRect = this.submenuContainer.getBoundingClientRect();
const computedStyles = getComputedStyle(this.parentData.parent.domNode);
const paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0;
if (this.expandDirection === Direction.Right) {
if (window.innerWidth <= boundingRect.right + childBoundingRect.width) {
@@ -793,7 +826,9 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
const isSelected = this.element && hasClass(this.element, 'focused');
const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;
this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : null;
if (this.submenuIndicator) {
this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : '';
}
if (this.parentData.submenu) {
this.parentData.submenu.style(this.menuStyle);
@@ -818,7 +853,9 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
class MenuSeparatorActionViewItem extends ActionViewItem {
style(style: IMenuStyles): void {
this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : null;
if (this.label) {
this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : '';
}
}
}
+41 -14
View File
@@ -20,6 +20,7 @@ import { withNullAsUndefined } from 'vs/base/common/types';
import { asArray } from 'vs/base/common/arrays';
import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
import { isMacintosh } from 'vs/base/common/platform';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
const $ = DOM.$;
@@ -55,7 +56,7 @@ export class MenuBar extends Disposable {
actions?: ReadonlyArray<IAction>;
}[];
private overflowMenu: {
private overflowMenu!: {
buttonElement: HTMLElement;
titleElement: HTMLElement;
label: string;
@@ -72,22 +73,22 @@ export class MenuBar extends Disposable {
private menuUpdater: RunOnceScheduler;
// Input-related
private _mnemonicsInUse: boolean;
private openedViaKeyboard: boolean;
private awaitingAltRelease: boolean;
private ignoreNextMouseUp: boolean;
private _mnemonicsInUse: boolean = false;
private openedViaKeyboard: boolean = false;
private awaitingAltRelease: boolean = false;
private ignoreNextMouseUp: boolean = false;
private mnemonics: Map<string, number>;
private updatePending: boolean;
private updatePending: boolean = false;
private _focusState: MenubarState;
private actionRunner: IActionRunner;
private readonly _onVisibilityChange: Emitter<boolean>;
private readonly _onFocusStateChange: Emitter<boolean>;
private numMenusShown: number;
private menuStyle: IMenuStyles;
private overflowLayoutScheduled: IDisposable | null;
private numMenusShown: number = 0;
private menuStyle: IMenuStyles | undefined;
private overflowLayoutScheduled: IDisposable | null = null;
constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) {
super();
@@ -252,7 +253,14 @@ export class MenuBar extends Disposable {
e.stopPropagation();
}));
this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e) => {
this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => {
// Ignore non-left-click
const mouseEvent = new StandardMouseEvent(e);
if (!mouseEvent.leftButton) {
e.preventDefault();
return;
}
if (!this.isOpen) {
// Open the menu with mouse down and ignore the following mouse up event
this.ignoreNextMouseUp = true;
@@ -266,6 +274,10 @@ export class MenuBar extends Disposable {
}));
this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => {
if (e.defaultPrevented) {
return;
}
if (!this.ignoreNextMouseUp) {
if (this.isFocused) {
this.onMenuTriggered(menuIndex, true);
@@ -337,6 +349,13 @@ export class MenuBar extends Disposable {
}));
this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e) => {
// Ignore non-left-click
const mouseEvent = new StandardMouseEvent(e);
if (!mouseEvent.leftButton) {
e.preventDefault();
return;
}
if (!this.isOpen) {
// Open the menu with mouse down and ignore the following mouse up event
this.ignoreNextMouseUp = true;
@@ -350,6 +369,10 @@ export class MenuBar extends Disposable {
}));
this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => {
if (e.defaultPrevented) {
return;
}
if (!this.ignoreNextMouseUp) {
if (this.isFocused) {
this.onMenuTriggered(MenuBar.OVERFLOW_INDEX, true);
@@ -462,9 +485,11 @@ export class MenuBar extends Disposable {
this.overflowMenu.actions.push(new SubmenuAction(this.menuCache[idx].label, this.menuCache[idx].actions || []));
}
DOM.removeNode(this.overflowMenu.buttonElement);
this.container.insertBefore(this.overflowMenu.buttonElement, this.menuCache[this.numMenusShown].buttonElement);
this.overflowMenu.buttonElement.style.visibility = 'visible';
if (this.overflowMenu.buttonElement.nextElementSibling !== this.menuCache[this.numMenusShown].buttonElement) {
DOM.removeNode(this.overflowMenu.buttonElement);
this.container.insertBefore(this.overflowMenu.buttonElement, this.menuCache[this.numMenusShown].buttonElement);
this.overflowMenu.buttonElement.style.visibility = 'visible';
}
} else {
DOM.removeNode(this.overflowMenu.buttonElement);
this.container.appendChild(this.overflowMenu.buttonElement);
@@ -913,7 +938,9 @@ export class MenuBar extends Disposable {
};
let menuWidget = this._register(new Menu(menuHolder, customMenu.actions, menuOptions));
menuWidget.style(this.menuStyle);
if (this.menuStyle) {
menuWidget.style(this.menuStyle);
}
this._register(menuWidget.onDidCancel(() => {
this.focusState = MenubarState.FOCUSED;
@@ -1,24 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { escape } from 'vs/base/common/strings';
export function renderOcticons(text: string): string {
return escape(text);
}
export class OcticonLabel {
private _container: HTMLElement;
constructor(container: HTMLElement) {
this._container = container;
}
set text(text: string) {
this._container.innerHTML = renderOcticons(text || '');
}
}
@@ -1,33 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./octicons/octicons';
import 'vs/css!./octicons/octicons-animations';
import { escape } from 'vs/base/common/strings';
function expand(text: string): string {
return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => {
return `<span class="octicon octicon-${name} ${animation ? `octicon-animation-${animation}` : ''}"></span>`;
});
}
export function renderOcticons(label: string): string {
return expand(escape(label));
}
export class OcticonLabel {
constructor(
private readonly _container: HTMLElement
) { }
set text(text: string) {
this._container.innerHTML = renderOcticons(text || '');
}
set title(title: string) {
this._container.title = title;
}
}
@@ -1,14 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@keyframes octicon-spin {
100% {
transform:rotate(360deg);
}
}
.octicon-animation-spin {
animation: octicon-spin 1.5s linear infinite;
}
@@ -1,251 +0,0 @@
@font-face {
font-family: "octicons";
src: url("./octicons.ttf?1829db8570ee0fa5a4bef3bb41d5f62e") format("truetype");
}
.octicon, .mega-octicon {
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mega-octicon { font-size: 32px; }
.octicon-alert:before { content: "\f02d" }
.octicon-arrow-down:before { content: "\f03f" }
.octicon-arrow-left:before { content: "\f040" }
.octicon-arrow-right:before { content: "\f03e" }
.octicon-arrow-small-down:before { content: "\f0a0" }
.octicon-arrow-small-left:before { content: "\f0a1" }
.octicon-arrow-small-right:before { content: "\f071" }
.octicon-arrow-small-up:before { content: "\f09f" }
.octicon-arrow-up:before { content: "\f03d" }
.octicon-beaker:before { content: "\f0dd" }
.octicon-bell:before { content: "\f0de" }
.octicon-bold:before { content: "\f282" }
.octicon-book:before { content: "\f007" }
.octicon-bookmark:before { content: "\f07b" }
.octicon-briefcase:before { content: "\f0d3" }
.octicon-broadcast:before { content: "\f048" }
.octicon-browser:before { content: "\f0c5" }
.octicon-bug:before { content: "\f091" }
.octicon-calendar:before { content: "\f068" }
.octicon-check:before { content: "\f03a" }
.octicon-checklist:before { content: "\f076" }
.octicon-chevron-down:before { content: "\f0a3" }
.octicon-chevron-left:before { content: "\f0a4" }
.octicon-chevron-right:before { content: "\f078" }
.octicon-chevron-up:before { content: "\f0a2" }
.octicon-circle-slash:before { content: "\f084" }
.octicon-circuit-board:before { content: "\f0d6" }
.octicon-clippy:before { content: "\f035" }
.octicon-clock:before { content: "\f046" }
.octicon-clone:before { content: "\f0dc" }
.octicon-cloud-download:before { content: "\f00b" }
.octicon-cloud-upload:before { content: "\f00c" }
.octicon-code:before { content: "\f05f" }
.octicon-color-mode:before { content: "\f065" }
.octicon-comment-add:before { content: "\f02b" }
.octicon-comment-discussion:before { content: "\f04f" }
.octicon-comment:before { content: "\f02b" }
.octicon-credit-card:before { content: "\f045" }
.octicon-dash:before { content: "\f0ca" }
.octicon-dashboard:before { content: "\f07d" }
.octicon-database:before { content: "\f096" }
.octicon-desktop-download:before { content: "\f0dc" }
.octicon-device-camera-video:before { content: "\f057" }
.octicon-device-camera:before { content: "\f056" }
.octicon-device-desktop:before { content: "\f27c" }
.octicon-device-mobile:before { content: "\f038" }
.octicon-diff-added:before { content: "\f06b" }
.octicon-diff-ignored:before { content: "\f099" }
.octicon-diff-modified:before { content: "\f06d" }
.octicon-diff-removed:before { content: "\f06c" }
.octicon-diff-renamed:before { content: "\f06e" }
.octicon-diff:before { content: "\f04d" }
.octicon-ellipsis:before { content: "\f09a" }
.octicon-eye-unwatch:before { content: "\f04e" }
.octicon-eye-watch:before { content: "\f04e" }
.octicon-eye:before { content: "\f04e" }
.octicon-file-add:before { content: "\f05d" }
.octicon-file-binary:before { content: "\f094" }
.octicon-file-code:before { content: "\f010" }
.octicon-file-directory-create:before { content: "\f05d" }
.octicon-file-directory:before { content: "\f016" }
.octicon-file-media:before { content: "\f012" }
.octicon-file-pdf:before { content: "\f014" }
.octicon-file-submodule:before { content: "\f017" }
.octicon-file-symlink-directory:before { content: "\f0b1" }
.octicon-file-symlink-file:before { content: "\f0b0" }
.octicon-file-text:before { content: "\f283" }
.octicon-file-zip:before { content: "\f013" }
.octicon-file:before { content: "\f283" }
.octicon-flame:before { content: "\f0d2" }
.octicon-fold:before { content: "\f0cc" }
.octicon-gear:before { content: "\f02f" }
.octicon-gift:before { content: "\f042" }
.octicon-gist-fork:before { content: "\f002" }
.octicon-gist-new:before { content: "\f05d" }
.octicon-gist-private:before { content: "\f06a" }
.octicon-gist-secret:before { content: "\f08c" }
.octicon-gist:before { content: "\f00e" }
.octicon-git-branch-create:before { content: "\f020" }
.octicon-git-branch-delete:before { content: "\f020" }
.octicon-git-branch:before { content: "\f020" }
.octicon-git-commit:before { content: "\f01f" }
.octicon-git-compare:before { content: "\f0ac" }
.octicon-git-fork-private:before { content: "\f06a" }
.octicon-git-merge:before { content: "\f023" }
.octicon-git-pull-request-abandoned:before { content: "\f009" }
.octicon-git-pull-request:before { content: "\f009" }
.octicon-globe:before { content: "\f0b6" }
.octicon-grabber:before { content: "\f284" }
.octicon-graph:before { content: "\f043" }
.octicon-heart:before { content: "\2665" }
.octicon-history:before { content: "\f07e" }
.octicon-home:before { content: "\f08d" }
.octicon-horizontal-rule:before { content: "\f070" }
.octicon-hubot:before { content: "\f09d" }
.octicon-inbox:before { content: "\f0cf" }
.octicon-info:before { content: "\f059" }
.octicon-issue-closed:before { content: "\f028" }
.octicon-issue-opened:before { content: "\f026" }
.octicon-issue-reopened:before { content: "\f027" }
.octicon-italic:before { content: "\f285" }
.octicon-jersey:before { content: "\f019" }
.octicon-kebab-horizontal:before { content: "\f286" }
.octicon-kebab-vertical:before { content: "\f287" }
.octicon-key:before { content: "\f049" }
.octicon-keyboard:before { content: "\f00d" }
.octicon-law:before { content: "\f0d8" }
.octicon-light-bulb:before { content: "\f000" }
.octicon-link-external:before { content: "\f07f" }
.octicon-link:before { content: "\f05c" }
.octicon-list-ordered:before { content: "\f062" }
.octicon-list-unordered:before { content: "\f061" }
.octicon-location:before { content: "\f060" }
.octicon-lock:before { content: "\f06a" }
.octicon-log-in:before { content: "\f036" }
.octicon-log-out:before { content: "\f032" }
.octicon-mail-read:before { content: "\f03c" }
.octicon-mail-reply:before { content: "\f28c" }
.octicon-mail:before { content: "\f03b" }
.octicon-logo-gist:before { content: "\f00a" }
.octicon-logo-github:before { content: "\f00a" }
.octicon-mark-github:before { content: "\f00a" }
.octicon-markdown:before { content: "\f0c9" }
.octicon-megaphone:before { content: "\f077" }
.octicon-mention:before { content: "\f0be" }
.octicon-microscope:before { content: "\f0dd" }
.octicon-milestone:before { content: "\f075" }
.octicon-mirror-private:before { content: "\f06a" }
.octicon-mirror-public:before { content: "\f024" }
.octicon-mirror:before { content: "\f024" }
.octicon-mortar-board:before { content: "\f0d7" }
.octicon-mute:before { content: "\f080" }
.octicon-no-newline:before { content: "\f09c" }
.octicon-note:before { content: "\f289" }
.octicon-octoface:before { content: "\f008" }
.octicon-organization:before { content: "\f037" }
.octicon-organization-filled:before { content: "\f037" }
.octicon-organization-outline:before { content: "\f037" }
.octicon-package:before { content: "\f0c4" }
.octicon-paintcan:before { content: "\f0d1" }
.octicon-pencil:before { content: "\f058" }
.octicon-person-add:before { content: "\f018" }
.octicon-person-follow:before { content: "\f018" }
.octicon-person:before { content: "\f018" }
.octicon-person-filled:before { content: "\f018" }
.octicon-person-outline:before { content: "\f018" }
.octicon-pin:before { content: "\f041" }
.octicon-plug:before { content: "\f0d4" }
.octicon-plus-small:before { content: "\f28a" }
.octicon-plus:before { content: "\f05d" }
.octicon-primitive-dot:before { content: "\f052" }
.octicon-primitive-square:before { content: "\f053" }
.octicon-project:before { content: "\f28b" }
.octicon-pulse:before { content: "\f085" }
.octicon-question:before { content: "\f02c" }
.octicon-quote:before { content: "\f063" }
.octicon-radio-tower:before { content: "\f030" }
.octicon-remove-close:before { content: "\f081" }
.octicon-reply:before { content: "\f28c" }
.octicon-repo-clone:before { content: "\f04c" }
.octicon-repo-create:before { content: "\f05d" }
.octicon-repo-delete:before { content: "\f001" }
.octicon-repo-force-push:before { content: "\f04a" }
.octicon-repo-forked:before { content: "\f002" }
.octicon-repo-pull:before { content: "\f006" }
.octicon-repo-push:before { content: "\f005" }
.octicon-repo-sync:before { content: "\f087" }
.octicon-repo:before { content: "\f001" }
.octicon-report:before { content: "\f28d" }
.octicon-rocket:before { content: "\f033" }
.octicon-rss:before { content: "\f034" }
.octicon-ruby:before { content: "\f047" }
.octicon-screen-full:before { content: "\f066" }
.octicon-screen-normal:before { content: "\f067" }
.octicon-search-save:before { content: "\f02e" }
.octicon-search:before { content: "\f02e" }
.octicon-server:before { content: "\f097" }
.octicon-settings:before { content: "\f07c" }
.octicon-shield:before { content: "\f0e1" }
.octicon-sign-in:before { content: "\f036" }
.octicon-sign-out:before { content: "\f032" }
.octicon-smiley:before { content: "\26b2" }
.octicon-squirrel:before { content: "\f0b2" }
.octicon-star-add:before { content: "\f02a" }
.octicon-star-delete:before { content: "\f02a" }
.octicon-star:before { content: "\f02a" }
.octicon-stop:before { content: "\f08f" }
.octicon-sync:before { content: "\f087" }
.octicon-tag-add:before { content: "\f015" }
.octicon-tag-remove:before { content: "\f015" }
.octicon-tag:before { content: "\f015" }
.octicon-tasklist:before { content: "\f27e" }
.octicon-telescope:before { content: "\f088" }
.octicon-terminal:before { content: "\f0c8" }
.octicon-text-size:before { content: "\f27f" }
.octicon-three-bars:before { content: "\f05e" }
.octicon-thumbsdown:before { content: "\f0db" }
.octicon-thumbsup:before { content: "\f0da" }
.octicon-tools:before { content: "\f031" }
.octicon-trashcan:before { content: "\f0d0" }
.octicon-triangle-down:before { content: "\f05b" }
.octicon-triangle-left:before { content: "\f044" }
.octicon-triangle-right:before { content: "\f05a" }
.octicon-triangle-up:before { content: "\f0aa" }
.octicon-unfold:before { content: "\f039" }
.octicon-unmute:before { content: "\f0ba" }
.octicon-unverified:before { content: "\f280" }
.octicon-verified:before { content: "\f281" }
.octicon-versions:before { content: "\f064" }
.octicon-watch:before { content: "\f0e0" }
.octicon-x:before { content: "\f081" }
.octicon-zap:before { content: "\26a1" }
.octicon-error:before { content: "\26b1" }
.octicon-eye-closed:before { content: "\26a3" }
.octicon-fold-down:before { content: "\26a4" }
.octicon-fold-up:before { content: "\26a5" }
.octicon-github-action:before { content: "\26a6" }
.octicon-info-outline:before { content: "\26a7" }
.octicon-play:before { content: "\26a8" }
.octicon-remote:before { content: "\26a9" }
.octicon-request-changes:before { content: "\26aa" }
.octicon-smiley-outline:before { content: "\26b2" }
.octicon-warning:before { content: "\f02d" }
.octicon-controls:before { content: "\26ad" }
.octicon-event:before { content: "\26ae" }
.octicon-record-keys:before { content: "\26af" }
.octicon-Vector:before { content: "\f101" }
.octicon-archive:before { content: "\f102" }
.octicon-arrow-both:before { content: "\f103" }
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./progressbar';
import * as assert from 'vs/base/common/assert';
import { Disposable } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
@@ -154,9 +153,7 @@ export class ProgressBar extends Disposable {
* Tells the progress bar that an increment of work has been completed.
*/
worked(value: number): ProgressBar {
value = Number(value);
assert.ok(!isNaN(value), 'Value is not a number');
value = Math.max(1, value);
value = Math.max(1, Number(value));
return this.doSetWorked(this.workedVal + value);
}
@@ -165,16 +162,13 @@ export class ProgressBar extends Disposable {
* Tells the progress bar the total amount of work that has been completed.
*/
setWorked(value: number): ProgressBar {
value = Number(value);
assert.ok(!isNaN(value), 'Value is not a number');
value = Math.max(1, value);
value = Math.max(1, Number(value));
return this.doSetWorked(value);
}
private doSetWorked(value: number): ProgressBar {
assert.ok(isNumber(this.totalWork), 'Total work not set');
const totalWork = this.totalWork!;
const totalWork = this.totalWork || 100;
this.workedVal = value;
this.workedVal = Math.min(totalWork, this.workedVal);
@@ -227,7 +221,7 @@ export class ProgressBar extends Disposable {
protected applyStyles(): void {
if (this.bit) {
const background = this.progressBarBackground ? this.progressBarBackground.toString() : null;
const background = this.progressBarBackground ? this.progressBarBackground.toString() : '';
this.bit.style.backgroundColor = background;
}
@@ -83,7 +83,7 @@ export class SelectBox extends Widget implements ISelectBoxDelegate {
super();
// Default to native SelectBox for OSX unless overridden
if (isMacintosh && !(selectBoxOptions && selectBoxOptions.useCustomDrawn)) {
if (isMacintosh && !selectBoxOptions?.useCustomDrawn) {
this.selectBoxDelegate = new SelectBoxNative(options, selected, styles, selectBoxOptions);
} else {
this.selectBoxDelegate = new SelectBoxList(options, selected, contextViewProvider, styles, selectBoxOptions);
@@ -381,22 +381,22 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
// Style parent select
// {{SQL CARBON EDIT}}
let background: Color | undefined = undefined;
let foreground: Color | undefined = undefined;
let border: Color | undefined = undefined;
let background = '';
let foreground = '';
let border = '';
if (this.selectElement) {
if (this.selectElement.disabled) {
background = (<any>this.styles).disabledSelectBackground;
foreground = (<any>this.styles).disabledSelectForeground;
background = (<any>this.styles).disabledSelectBackground ? (<any>this.styles).disabledSelectBackground.toString() : '';
foreground = (<any>this.styles).disabledSelectForeground ? (<any>this.styles).disabledSelectForeground.toString() : '';
} else {
background = this.styles.selectBackground;
foreground = this.styles.selectForeground;
border = this.styles.selectBorder;
background = this.styles.selectBackground ? this.styles.selectBackground.toString() : '';
foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : '';
border = this.styles.selectBorder ? this.styles.selectBorder.toString() : '';
}
this.selectElement.style.backgroundColor = background ? background.toString() : null;
this.selectElement.style.color = foreground ? foreground.toString() : null;
this.selectElement.style.borderColor = border ? border.toString() : null;
this.selectElement.style.backgroundColor = background;
this.selectElement.style.color = foreground;
this.selectElement.style.borderColor = border;
}
// Style drop down select list (non-native mode only)
@@ -408,10 +408,10 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
private styleList() {
if (this.selectList) {
let background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null;
const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : '';
this.selectList.style({});
let listBackground = this.styles.selectListBackground ? this.styles.selectListBackground.toString() : background;
const listBackground = this.styles.selectListBackground ? this.styles.selectListBackground.toString() : background;
this.selectDropDownListContainer.style.backgroundColor = listBackground;
this.selectionDetailsPane.style.backgroundColor = listBackground;
const optionsBorder = this.styles.focusBorder ? this.styles.focusBorder.toString() : '';
@@ -148,9 +148,9 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
// Style native select
if (this.selectElement) {
const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null;
const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : null;
const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : null;
const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : '';
const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : '';
const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : '';
this.selectElement.style.backgroundColor = background;
this.selectElement.style.color = foreground;
@@ -32,6 +32,7 @@
justify-content: center;
transform-origin: center;
color: inherit;
flex-shrink: 0;
}
.monaco-panel-view .panel > .panel-header.expanded > .twisties::before {
+9 -11
View File
@@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { $, append, addClass, removeClass, toggleClass, trackFocus, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { $, append, addClass, removeClass, toggleClass, trackFocus } from 'vs/base/browser/dom';
import { firstIndex } from 'vs/base/common/arrays';
import { Color, RGBA } from 'vs/base/common/color';
import { SplitView, IView } from './splitview';
@@ -58,6 +58,9 @@ export abstract class Panel extends Disposable implements IView {
private readonly _onDidChange = this._register(new Emitter<number | undefined>());
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
private readonly _onDidChangeExpansionState = this._register(new Emitter<boolean>());
readonly onDidChangeExpansionState: Event<boolean> = this._onDidChangeExpansionState.event;
get draggableElement(): HTMLElement {
return this.header;
}
@@ -144,6 +147,7 @@ export abstract class Panel extends Disposable implements IView {
}, 200);
}
this._onDidChangeExpansionState.fire(expanded);
this._onDidChange.fire(expanded ? this.expandedSize : undefined);
return true;
}
@@ -225,8 +229,8 @@ export abstract class Panel extends Disposable implements IView {
this.header.setAttribute('aria-expanded', String(expanded));
this.header.style.color = this.styles.headerForeground ? this.styles.headerForeground.toString() : null;
this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : null;
this.header.style.borderTop = this.styles.headerBorder ? `1px solid ${this.styles.headerBorder}` : null;
this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : '';
this.header.style.borderTop = this.styles.headerBorder ? `1px solid ${this.styles.headerBorder}` : '';
this._dropBackground = this.styles.dropBackground;
}
@@ -336,7 +340,7 @@ class PanelDraggable extends Disposable {
backgroundColor = (this.panel.dropBackground || PanelDraggable.DefaultDragOverBackgroundColor).toString();
}
this.panel.dropTargetElement.style.backgroundColor = backgroundColor;
this.panel.dropTargetElement.style.backgroundColor = backgroundColor || '';
}
}
@@ -391,13 +395,7 @@ export class PanelView extends Disposable {
addPanel(panel: Panel, size: number, index = this.splitview.length): void {
const disposables = new DisposableStore();
// https://github.com/Microsoft/vscode/issues/59950
let shouldAnimate = false;
disposables.add(scheduleAtNextAnimationFrame(() => shouldAnimate = true));
disposables.add(Event.filter(panel.onDidChange, () => shouldAnimate)
(this.setupAnimation, this));
panel.onDidChangeExpansionState(this.setupAnimation, this, disposables);
const panelItem = { panel, disposable: disposables };
this.panelItems.splice(index, 0, panelItem);
+2 -2
View File
@@ -129,9 +129,9 @@ export class ToolBar extends Disposable {
}
private getKeybindingLabel(action: IAction): string | undefined {
const key = this.lookupKeybindings && this.options.getKeyBinding ? this.options.getKeyBinding(action) : undefined;
const key = this.lookupKeybindings ? this.options.getKeyBinding?.(action) : undefined;
return withNullAsUndefined(key && key.getLabel());
return withNullAsUndefined(key?.getLabel());
}
addPrimaryAction(primaryAction: IAction): () => void {
+30 -22
View File
@@ -238,7 +238,7 @@ class EventCollection<T> implements Collection<T> {
class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer<ITreeNode<T, TFilterData>, ITreeListTemplateData<TTemplateData>> {
private static DefaultIndent = 8;
private static readonly DefaultIndent = 8;
readonly templateId: string;
private renderedElements = new Map<T, ITreeNode<T, TFilterData>>();
@@ -250,7 +250,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
private activeIndentNodes = new Set<ITreeNode<T, TFilterData>>();
private indentGuidesDisposable: IDisposable = Disposable.None;
private disposables: IDisposable[] = [];
private readonly disposables = new DisposableStore();
constructor(
private renderer: ITreeRenderer<T, TFilterData, TTemplateData>,
@@ -458,7 +458,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
this.renderedNodes.clear();
this.renderedElements.clear();
this.indentGuidesDisposable.dispose();
this.disposables = dispose(this.disposables);
dispose(this.disposables);
}
}
@@ -471,7 +471,7 @@ class TypeFilter<T> implements ITreeFilter<T, FuzzyScore>, IDisposable {
private _pattern: string = '';
private _lowercasePattern: string = '';
private disposables: IDisposable[] = [];
private readonly disposables = new DisposableStore();
set pattern(pattern: string) {
this._pattern = pattern;
@@ -546,7 +546,7 @@ class TypeFilter<T> implements ITreeFilter<T, FuzzyScore>, IDisposable {
}
dispose(): void {
this.disposables = dispose(this.disposables);
dispose(this.disposables);
}
}
@@ -581,8 +581,8 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
private readonly _onDidChangePattern = new Emitter<string>();
readonly onDidChangePattern = this._onDidChangePattern.event;
private enabledDisposables: IDisposable[] = [];
private disposables: IDisposable[] = [];
private readonly enabledDisposables = new DisposableStore();
private readonly disposables = new DisposableStore();
constructor(
private tree: AbstractTree<T, TFilterData, any>,
@@ -657,6 +657,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown'))
.filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode)
.filter(e => e.key !== 'Dead')
.map(e => new StandardKeyboardEvent(e))
.filter(this.keyboardNavigationEventFilter || (() => true))
.filter(() => this.automaticKeyboardNavigation || this.triggered)
@@ -682,7 +683,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
}
this.domNode.remove();
this.enabledDisposables = dispose(this.enabledDisposables);
this.enabledDisposables.clear();
this.tree.refilter();
this.render();
this._enabled = false;
@@ -744,7 +745,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
const containerWidth = container.clientWidth;
const midContainerWidth = containerWidth / 2;
const width = this.domNode.clientWidth;
const disposables: IDisposable[] = [];
const disposables = new DisposableStore();
let positionClassName = this.positionClassName;
const updatePosition = () => {
@@ -780,8 +781,8 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
const onDragEnd = () => {
this.positionClassName = positionClassName;
this.domNode.className = `monaco-list-type-filter ${this.positionClassName}`;
this.domNode.style.top = null;
this.domNode.style.left = null;
this.domNode.style.top = '';
this.domNode.style.left = '';
dispose(disposables);
};
@@ -790,13 +791,13 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
removeClass(this.domNode, positionClassName);
addClass(this.domNode, 'dragging');
disposables.push(toDisposable(() => removeClass(this.domNode, 'dragging')));
disposables.add(toDisposable(() => removeClass(this.domNode, 'dragging')));
domEvent(document, 'dragover')(onDragOver, null, disposables);
domEvent(this.domNode, 'dragend')(onDragEnd, null, disposables);
StaticDND.CurrentDragAndDropData = new DragAndDropData('vscode-ui');
disposables.push(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined));
disposables.add(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined));
}
private onDidSpliceModel(): void {
@@ -855,9 +856,15 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
}
dispose() {
this.disable();
if (this._enabled) {
this.domNode.remove();
this.enabledDisposables.dispose();
this._enabled = false;
this.triggered = false;
}
this._onDidChangePattern.dispose();
this.disposables = dispose(this.disposables);
dispose(this.disposables);
}
}
@@ -1175,7 +1182,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
private typeFilterController?: TypeFilterController<T, TFilterData>;
private focusNavigationFilter: ((node: ITreeNode<T, TFilterData>) => boolean) | undefined;
private styleElement: HTMLStyleElement;
protected disposables: IDisposable[] = [];
protected readonly disposables = new DisposableStore();
get onDidScroll(): Event<ScrollEvent> { return this.view.onDidScroll; }
@@ -1224,16 +1231,17 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const onDidChangeCollapseStateRelay = new Relay<ICollapseStateChangeEvent<T, TFilterData>>();
const onDidChangeActiveNodes = new Relay<ITreeNode<T, TFilterData>[]>();
const activeNodes = new EventCollection(onDidChangeActiveNodes.event);
this.renderers = renderers.map(r => new TreeRenderer<T, TFilterData, TRef, any>(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));
this.disposables.push(...this.renderers);
for (let r of this.renderers) {
this.disposables.add(r);
}
let filter: TypeFilter<T> | undefined;
if (_options.keyboardNavigationLabelProvider) {
filter = new TypeFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter<T, FuzzyScore>);
_options = { ..._options, filter: filter as ITreeFilter<T, TFilterData> }; // TODO need typescript help here
this.disposables.push(filter);
this.disposables.add(filter);
}
this.focus = new Trait(_options.identityProvider);
@@ -1287,7 +1295,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate;
this.typeFilterController = new TypeFilterController(this, this.model, this.view, filter!, delegate);
this.focusNavigationFilter = node => this.typeFilterController!.shouldAllowFocus(node);
this.disposables.push(this.typeFilterController!);
this.disposables.add(this.typeFilterController!);
}
this.styleElement = createStyleSheet(this.view.getHTMLElement());
@@ -1362,7 +1370,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
}
get scrollLeft(): number {
return this.view.scrollTop;
return this.view.scrollLeft;
}
set scrollLeft(scrollLeft: number) {
@@ -1641,7 +1649,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
}
dispose(): void {
this.disposables = dispose(this.disposables);
dispose(this.disposables);
this.view.dispose();
}
}
+3 -5
View File
@@ -7,7 +7,7 @@ import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate
import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree';
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list';
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper } from 'vs/base/browser/ui/tree/tree';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
@@ -88,7 +88,6 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
readonly templateId: string;
private renderedNodes = new Map<IAsyncDataTreeNode<TInput, T>, IDataTreeListTemplateData<TTemplateData>>();
private disposables: IDisposable[] = [];
constructor(
protected renderer: ITreeRenderer<T, TFilterData, TTemplateData>,
@@ -124,7 +123,6 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
dispose(): void {
this.renderedNodes.clear();
this.disposables = dispose(this.disposables);
}
}
@@ -292,7 +290,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
protected readonly nodeMapper: AsyncDataTreeNodeMapper<TInput, T, TFilterData> = new WeakMapper(node => new AsyncDataTreeNodeWrapper(node));
protected readonly disposables: IDisposable[] = [];
protected readonly disposables = new DisposableStore();
get onDidScroll(): Event<ScrollEvent> { return this.tree.onDidScroll; }
@@ -930,7 +928,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
}
dispose(): void {
dispose(this.disposables);
this.disposables.dispose();
}
}
+3 -6
View File
@@ -14,7 +14,7 @@ import { CompressibleObjectTreeModel, ElementMapper, ICompressedTreeNode, ICompr
import { memoize } from 'vs/base/common/decorators';
export interface IObjectTreeOptions<T, TFilterData = void> extends IAbstractTreeOptions<T, TFilterData> {
sorter?: ITreeSorter<T>;
readonly sorter?: ITreeSorter<T>;
}
export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends AbstractTree<T | null, TFilterData, T | null> {
@@ -59,10 +59,6 @@ interface ICompressedTreeNodeProvider<T, TFilterData> {
getCompressedTreeNode(element: T): ITreeNode<ICompressedTreeNode<T>, TFilterData>;
}
export interface ICompressibleObjectTreeOptions<T, TFilterData = void> extends IObjectTreeOptions<T, TFilterData> {
readonly elementMapper?: ElementMapper<T>;
}
export interface ICompressibleTreeRenderer<T, TFilterData = void, TTemplateData = void> extends ITreeRenderer<T, TFilterData, TTemplateData> {
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<T>, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;
disposeCompressedElements?(node: ITreeNode<ICompressedTreeNode<T>, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;
@@ -136,6 +132,7 @@ export interface ICompressibleKeyboardNavigationLabelProvider<T> extends IKeyboa
}
export interface ICompressibleObjectTreeOptions<T, TFilterData = void> extends IObjectTreeOptions<T, TFilterData> {
readonly elementMapper?: ElementMapper<T>;
readonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider<T>;
}
@@ -164,7 +161,7 @@ function asObjectTreeOptions<T, TFilterData>(compressedTreeNodeProvider: () => I
export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> implements ICompressedTreeNodeProvider<T, TFilterData> {
protected model: CompressibleObjectTreeModel<T, TFilterData>;
protected model!: CompressibleObjectTreeModel<T, TFilterData>;
constructor(
user: string,
-18
View File
@@ -29,7 +29,6 @@ export interface IAction extends IDisposable {
class: string | undefined;
enabled: boolean;
checked: boolean;
radio: boolean;
run(event?: any): Promise<any>;
}
@@ -54,7 +53,6 @@ export interface IActionChangeEvent {
readonly class?: string;
readonly enabled?: boolean;
readonly checked?: boolean;
readonly radio?: boolean;
}
export class Action extends Disposable implements IAction {
@@ -68,7 +66,6 @@ export class Action extends Disposable implements IAction {
protected _cssClass: string | undefined;
protected _enabled: boolean = true;
protected _checked: boolean = false;
protected _radio: boolean = false;
protected readonly _actionCallback?: (event?: any) => Promise<any>;
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise<any>) {
@@ -152,14 +149,6 @@ export class Action extends Disposable implements IAction {
this._setChecked(value);
}
get radio(): boolean {
return this._radio;
}
set radio(value: boolean) {
this._setRadio(value);
}
protected _setChecked(value: boolean): void {
if (this._checked !== value) {
this._checked = value;
@@ -167,13 +156,6 @@ export class Action extends Disposable implements IAction {
}
}
protected _setRadio(value: boolean): void {
if (this._radio !== value) {
this._radio = value;
this._onDidChange.fire({ radio: value });
}
}
run(event?: any, _data?: ITelemetryData): Promise<any> {
if (this._actionCallback) {
return this._actionCallback(event);
+4 -1
View File
@@ -116,7 +116,10 @@ export class CancellationTokenSource {
}
}
dispose(): void {
dispose(cancel: boolean = false): void {
if (cancel) {
this.cancel();
}
if (this._parentListener) {
this._parentListener.dispose();
}
+135
View File
@@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { matchesFuzzy, IMatch } from 'vs/base/common/filters';
import { ltrim } from 'vs/base/common/strings';
const codiconStartMarker = '$(';
export interface IParsedCodicons {
readonly text: string;
readonly codiconOffsets?: readonly number[];
}
export function parseCodicons(text: string): IParsedCodicons {
const firstCodiconIndex = text.indexOf(codiconStartMarker);
if (firstCodiconIndex === -1) {
return { text }; // return early if the word does not include an codicon
}
return doParseCodicons(text, firstCodiconIndex);
}
function doParseCodicons(text: string, firstCodiconIndex: number): IParsedCodicons {
const codiconOffsets: number[] = [];
let textWithoutCodicons: string = '';
function appendChars(chars: string) {
if (chars) {
textWithoutCodicons += chars;
for (const _ of chars) {
codiconOffsets.push(codiconsOffset); // make sure to fill in codicon offsets
}
}
}
let currentCodiconStart = -1;
let currentCodiconValue: string = '';
let codiconsOffset = 0;
let char: string;
let nextChar: string;
let offset = firstCodiconIndex;
const length = text.length;
// Append all characters until the first codicon
appendChars(text.substr(0, firstCodiconIndex));
// example: $(file-symlink-file) my cool $(other-codicon) entry
while (offset < length) {
char = text[offset];
nextChar = text[offset + 1];
// beginning of codicon: some value $( <--
if (char === codiconStartMarker[0] && nextChar === codiconStartMarker[1]) {
currentCodiconStart = offset;
// if we had a previous potential codicon value without
// the closing ')', it was actually not an codicon and
// so we have to add it to the actual value
appendChars(currentCodiconValue);
currentCodiconValue = codiconStartMarker;
offset++; // jump over '('
}
// end of codicon: some value $(some-codicon) <--
else if (char === ')' && currentCodiconStart !== -1) {
const currentCodiconLength = offset - currentCodiconStart + 1; // +1 to include the closing ')'
codiconsOffset += currentCodiconLength;
currentCodiconStart = -1;
currentCodiconValue = '';
}
// within codicon
else if (currentCodiconStart !== -1) {
// Make sure this is a real codicon name
if (/^[a-z0-9\-]$/i.test(char)) {
currentCodiconValue += char;
} else {
// This is not a real codicon, treat it as text
appendChars(currentCodiconValue);
currentCodiconStart = -1;
currentCodiconValue = '';
}
}
// any value outside of codicons
else {
appendChars(char);
}
offset++;
}
// if we had a previous potential codicon value without
// the closing ')', it was actually not an codicon and
// so we have to add it to the actual value
appendChars(currentCodiconValue);
return { text: textWithoutCodicons, codiconOffsets };
}
export function matchesFuzzyCodiconAware(query: string, target: IParsedCodicons, enableSeparateSubstringMatching = false): IMatch[] | null {
const { text, codiconOffsets } = target;
// Return early if there are no codicon markers in the word to match against
if (!codiconOffsets || codiconOffsets.length === 0) {
return matchesFuzzy(query, text, enableSeparateSubstringMatching);
}
// Trim the word to match against because it could have leading
// whitespace now if the word started with an codicon
const wordToMatchAgainstWithoutCodiconsTrimmed = ltrim(text, ' ');
const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutCodiconsTrimmed.length;
// match on value without codicons
const matches = matchesFuzzy(query, wordToMatchAgainstWithoutCodiconsTrimmed, enableSeparateSubstringMatching);
// Map matches back to offsets with codicons and trimming
if (matches) {
for (const match of matches) {
const codiconOffset = codiconOffsets[match.start + leadingWhitespaceOffset] /* codicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
match.start += codiconOffset;
match.end += codiconOffset;
}
}
return matches;
}
-9
View File
@@ -507,10 +507,6 @@ export namespace Color {
* The default format will use HEX if opaque and RGBA otherwise.
*/
export function format(color: Color): string | null {
if (!color) {
return null;
}
if (color.isOpaque()) {
return Color.Format.CSS.formatHex(color);
}
@@ -524,11 +520,6 @@ export namespace Color {
* @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).
*/
export function parseHex(hex: string): Color | null {
if (!hex) {
// Invalid color
return null;
}
const length = hex.length;
if (length === 0) {
+159 -103
View File
@@ -4,22 +4,29 @@
*--------------------------------------------------------------------------------------------*/
import { DiffChange } from 'vs/base/common/diff/diffChange';
import { stringHash } from 'vs/base/common/hash';
import { Constants } from 'vs/base/common/uint';
function createStringSequence(a: string): ISequence {
return {
getLength() { return a.length; },
getElementAtIndex(pos: number) { return a.charCodeAt(pos); }
};
export class StringDiffSequence implements ISequence {
constructor(private source: string) { }
getElements(): Int32Array | number[] | string[] {
const source = this.source;
const characters = new Int32Array(source.length);
for (let i = 0, len = source.length; i < len; i++) {
characters[i] = source.charCodeAt(i);
}
return characters;
}
}
export function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {
return new LcsDiff(createStringSequence(original), createStringSequence(modified)).ComputeDiff(pretty);
return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;
}
export interface ISequence {
getLength(): number;
getElementAtIndex(index: number): number | string;
getElements(): Int32Array | number[] | string[];
}
export interface IDiffChange {
@@ -49,7 +56,12 @@ export interface IDiffChange {
}
export interface IContinueProcessingPredicate {
(furthestOriginalIndex: number, originalSequence: ISequence, matchLengthOfLongest: number): boolean;
(furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;
}
export interface IDiffResult {
quitEarly: boolean;
changes: IDiffChange[];
}
//
@@ -86,6 +98,11 @@ export class MyArray {
destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
}
}
public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) {
for (let i = 0; i < length; i++) {
destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
}
}
}
//*****************************************************************************
@@ -100,11 +117,9 @@ export class MyArray {
// Our total memory usage for storing history is (worst-case):
// 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)
// 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB
let MaxDifferencesHistory = 1447;
//let MaxDifferencesHistory = 100;
const enum LocalConstants {
MaxDifferencesHistory = 1447
}
/**
* A utility class which helps to create the set of DiffChanges from
@@ -127,8 +142,8 @@ class DiffChangeHelper {
*/
constructor() {
this.m_changes = [];
this.m_originalStart = Number.MAX_VALUE;
this.m_modifiedStart = Number.MAX_VALUE;
this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_originalCount = 0;
this.m_modifiedCount = 0;
}
@@ -147,8 +162,8 @@ class DiffChangeHelper {
// Reset for the next change
this.m_originalCount = 0;
this.m_modifiedCount = 0;
this.m_originalStart = Number.MAX_VALUE;
this.m_modifiedStart = Number.MAX_VALUE;
this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
}
/**
@@ -214,39 +229,81 @@ class DiffChangeHelper {
*/
export class LcsDiff {
private OriginalSequence: ISequence;
private ModifiedSequence: ISequence;
private ContinueProcessingPredicate: IContinueProcessingPredicate | null;
private readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;
private m_forwardHistory: number[][];
private m_reverseHistory: number[][];
private readonly _hasStrings: boolean;
private readonly _originalStringElements: string[];
private readonly _originalElementsOrHash: Int32Array;
private readonly _modifiedStringElements: string[];
private readonly _modifiedElementsOrHash: Int32Array;
private m_forwardHistory: Int32Array[];
private m_reverseHistory: Int32Array[];
/**
* Constructs the DiffFinder
*/
constructor(originalSequence: ISequence, newSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
this.OriginalSequence = originalSequence;
this.ModifiedSequence = newSequence;
constructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
this.ContinueProcessingPredicate = continueProcessingPredicate;
const [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence);
const [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence);
this._hasStrings = (originalHasStrings && modifiedHasStrings);
this._originalStringElements = originalStringElements;
this._originalElementsOrHash = originalElementsOrHash;
this._modifiedStringElements = modifiedStringElements;
this._modifiedElementsOrHash = modifiedElementsOrHash;
this.m_forwardHistory = [];
this.m_reverseHistory = [];
}
private static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {
return (arr.length > 0 && typeof arr[0] === 'string');
}
private static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {
const elements = sequence.getElements();
if (LcsDiff._isStringArray(elements)) {
const hashes = new Int32Array(elements.length);
for (let i = 0, len = elements.length; i < len; i++) {
hashes[i] = stringHash(elements[i], 0);
}
return [elements, hashes, true];
}
if (elements instanceof Int32Array) {
return [[], elements, false];
}
return [[], new Int32Array(elements), false];
}
private ElementsAreEqual(originalIndex: number, newIndex: number): boolean {
return (this.OriginalSequence.getElementAtIndex(originalIndex) === this.ModifiedSequence.getElementAtIndex(newIndex));
if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {
return false;
}
return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);
}
private OriginalElementsAreEqual(index1: number, index2: number): boolean {
return (this.OriginalSequence.getElementAtIndex(index1) === this.OriginalSequence.getElementAtIndex(index2));
if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {
return false;
}
return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);
}
private ModifiedElementsAreEqual(index1: number, index2: number): boolean {
return (this.ModifiedSequence.getElementAtIndex(index1) === this.ModifiedSequence.getElementAtIndex(index2));
if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {
return false;
}
return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);
}
public ComputeDiff(pretty: boolean): IDiffChange[] {
return this._ComputeDiff(0, this.OriginalSequence.getLength() - 1, 0, this.ModifiedSequence.getLength() - 1, pretty);
public ComputeDiff(pretty: boolean): IDiffResult {
return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);
}
/**
@@ -254,18 +311,21 @@ export class LcsDiff {
* sequences on the bounded range.
* @returns An array of the differences between the two input sequences.
*/
private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): DiffChange[] {
let quitEarlyArr = [false];
private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {
const quitEarlyArr = [false];
let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);
if (pretty) {
// We have to clean up the computed diff to be more intuitive
// but it turns out this cannot be done correctly until the entire set
// of diffs have been computed
return this.PrettifyChanges(changes);
changes = this.PrettifyChanges(changes);
}
return changes;
return {
quitEarly: quitEarlyArr[0],
changes: changes
};
}
/**
@@ -318,11 +378,12 @@ export class LcsDiff {
}
// This problem can be solved using the Divide-And-Conquer technique.
let midOriginalArr = [0], midModifiedArr = [0];
let result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);
const midOriginalArr = [0];
const midModifiedArr = [0];
const result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);
let midOriginal = midOriginalArr[0];
let midModified = midModifiedArr[0];
const midOriginal = midOriginalArr[0];
const midModified = midModifiedArr[0];
if (result !== null) {
// Result is not-null when there was enough memory to compute the changes while
@@ -334,7 +395,7 @@ export class LcsDiff {
// Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd)
// NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point
let leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);
const leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);
let rightChanges: DiffChange[] = [];
if (!quitEarlyArr[0]) {
@@ -358,24 +419,25 @@ export class LcsDiff {
private WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,
diagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,
forwardPoints: number[], reversePoints: number[],
forwardPoints: Int32Array, reversePoints: Int32Array,
originalIndex: number, originalEnd: number, midOriginalArr: number[],
modifiedIndex: number, modifiedEnd: number, midModifiedArr: number[],
deltaIsEven: boolean, quitEarlyArr: boolean[]): DiffChange[] {
let forwardChanges: DiffChange[] | null = null, reverseChanges: DiffChange[] | null = null;
deltaIsEven: boolean, quitEarlyArr: boolean[]
): DiffChange[] {
let forwardChanges: DiffChange[] | null = null;
let reverseChanges: DiffChange[] | null = null;
// First, walk backward through the forward diagonals history
let changeHelper = new DiffChangeHelper();
let diagonalMin = diagonalForwardStart;
let diagonalMax = diagonalForwardEnd;
let diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset;
let lastOriginalIndex = Number.MIN_VALUE;
let lastOriginalIndex = Constants.MIN_SAFE_SMALL_INTEGER;
let historyIndex = this.m_forwardHistory.length - 1;
let diagonal: number;
do {
// Get the diagonal index from the relative diagonal number
diagonal = diagonalRelative + diagonalForwardBase;
const diagonal = diagonalRelative + diagonalForwardBase;
// Figure out where we came from
if (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {
@@ -420,7 +482,7 @@ export class LcsDiff {
let modifiedStartPoint = midModifiedArr[0] + 1;
if (forwardChanges !== null && forwardChanges.length > 0) {
let lastForwardChange = forwardChanges[forwardChanges.length - 1];
const lastForwardChange = forwardChanges[forwardChanges.length - 1];
originalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd());
modifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd());
}
@@ -435,12 +497,12 @@ export class LcsDiff {
diagonalMin = diagonalReverseStart;
diagonalMax = diagonalReverseEnd;
diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset;
lastOriginalIndex = Number.MAX_VALUE;
lastOriginalIndex = Constants.MAX_SAFE_SMALL_INTEGER;
historyIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2;
do {
// Get the diagonal index from the relative diagonal number
diagonal = diagonalRelative + diagonalReverseBase;
const diagonal = diagonalRelative + diagonalReverseBase;
// Figure out where we came from
if (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {
@@ -501,7 +563,6 @@ export class LcsDiff {
let originalIndex = 0, modifiedIndex = 0;
let diagonalForwardStart = 0, diagonalForwardEnd = 0;
let diagonalReverseStart = 0, diagonalReverseEnd = 0;
let numDifferences: number;
// To traverse the edit graph and produce the proper LCS, our actual
// start position is just outside the given boundary
@@ -521,26 +582,26 @@ export class LcsDiff {
// The integer value in the cell represents the originalIndex of the furthest
// reaching point found so far that ends in that diagonal.
// The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number.
let maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);
let numDiagonals = maxDifferences + 1;
let forwardPoints: number[] = new Array<number>(numDiagonals);
let reversePoints: number[] = new Array<number>(numDiagonals);
const maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);
const numDiagonals = maxDifferences + 1;
const forwardPoints = new Int32Array(numDiagonals);
const reversePoints = new Int32Array(numDiagonals);
// diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart)
// diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd)
let diagonalForwardBase = (modifiedEnd - modifiedStart);
let diagonalReverseBase = (originalEnd - originalStart);
const diagonalForwardBase = (modifiedEnd - modifiedStart);
const diagonalReverseBase = (originalEnd - originalStart);
// diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
// diagonal number (relative to diagonalForwardBase)
// diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
// diagonal number (relative to diagonalReverseBase)
let diagonalForwardOffset = (originalStart - modifiedStart);
let diagonalReverseOffset = (originalEnd - modifiedEnd);
const diagonalForwardOffset = (originalStart - modifiedStart);
const diagonalReverseOffset = (originalEnd - modifiedEnd);
// delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers
// relative to the start diagonal with diagonal numbers relative to the end diagonal.
// The Even/Oddn-ness of this delta is important for determining when we should check for overlap
let delta = diagonalReverseBase - diagonalForwardBase;
let deltaIsEven = (delta % 2 === 0);
const delta = diagonalReverseBase - diagonalForwardBase;
const deltaIsEven = (delta % 2 === 0);
// Here we set up the start and end points as the furthest points found so far
// in both the forward and reverse directions, respectively
@@ -559,15 +620,14 @@ export class LcsDiff {
// away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse).
// --We extend on even diagonals (relative to the reference diagonal) only when numDifferences
// is even and odd diagonals only when numDifferences is odd.
let diagonal: number, tempOriginalIndex: number;
for (numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {
for (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {
let furthestOriginalIndex = 0;
let furthestModifiedIndex = 0;
// Run the algorithm in the forward direction
diagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
diagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
for (diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {
for (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {
// STEP 1: We extend the furthest reaching point in the present diagonal
// by looking at the diagonals above and below and picking the one whose point
// is further away from the start point (originalStart, modifiedStart)
@@ -579,7 +639,7 @@ export class LcsDiff {
modifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset;
// Save the current originalIndex so we can test for false overlap in step 3
tempOriginalIndex = originalIndex;
const tempOriginalIndex = originalIndex;
// STEP 2: We can continue to extend the furthest reaching point in the present diagonal
// so long as the elements are equal.
@@ -603,7 +663,7 @@ export class LcsDiff {
midOriginalArr[0] = originalIndex;
midModifiedArr[0] = modifiedIndex;
if (tempOriginalIndex <= reversePoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (tempOriginalIndex <= reversePoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// BINGO! We overlapped, and we have the full trace in memory!
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -622,9 +682,9 @@ export class LcsDiff {
}
// Check to see if we should be quitting early, before moving on to the next iteration.
let matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;
const matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;
if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, this.OriginalSequence, matchLengthOfLongest)) {
if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) {
// We can't finish, so skip ahead to generating a result from what we have.
quitEarlyArr[0] = true;
@@ -632,7 +692,7 @@ export class LcsDiff {
midOriginalArr[0] = furthestOriginalIndex;
midModifiedArr[0] = furthestModifiedIndex;
if (matchLengthOfLongest > 0 && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (matchLengthOfLongest > 0 && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// Enough of the history is in memory to walk it backwards
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -659,7 +719,7 @@ export class LcsDiff {
// Run the algorithm in the reverse direction
diagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
diagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
for (diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {
for (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {
// STEP 1: We extend the furthest reaching point in the present diagonal
// by looking at the diagonals above and below and picking the one whose point
// is further away from the start point (originalEnd, modifiedEnd)
@@ -671,7 +731,7 @@ export class LcsDiff {
modifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset;
// Save the current originalIndex so we can test for false overlap
tempOriginalIndex = originalIndex;
const tempOriginalIndex = originalIndex;
// STEP 2: We can continue to extend the furthest reaching point in the present diagonal
// as long as the elements are equal.
@@ -689,7 +749,7 @@ export class LcsDiff {
midOriginalArr[0] = originalIndex;
midModifiedArr[0] = modifiedIndex;
if (tempOriginalIndex >= forwardPoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (tempOriginalIndex >= forwardPoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// BINGO! We overlapped, and we have the full trace in memory!
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -708,24 +768,22 @@ export class LcsDiff {
}
// Save current vectors to history before the next iteration
if (numDifferences <= MaxDifferencesHistory) {
if (numDifferences <= LocalConstants.MaxDifferencesHistory) {
// We are allocating space for one extra int, which we fill with
// the index of the diagonal base index
let temp: number[] = new Array<number>(diagonalForwardEnd - diagonalForwardStart + 2);
let temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2);
temp[0] = diagonalForwardBase - diagonalForwardStart + 1;
MyArray.Copy(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);
MyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);
this.m_forwardHistory.push(temp);
temp = new Array<number>(diagonalReverseEnd - diagonalReverseStart + 2);
temp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2);
temp[0] = diagonalReverseBase - diagonalReverseStart + 1;
MyArray.Copy(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);
MyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);
this.m_reverseHistory.push(temp);
}
}
// If we got here, then we have the full trace in history. We just have to convert it to a change list
// NOTE: This part is a bit messy
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
@@ -750,8 +808,8 @@ export class LcsDiff {
// Shift all the changes down first
for (let i = 0; i < changes.length; i++) {
const change = changes[i];
const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this.OriginalSequence.getLength();
const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this.ModifiedSequence.getLength();
const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length;
const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length;
const checkOriginal = change.originalLength > 0;
const checkModified = change.modifiedLength > 0;
@@ -795,8 +853,8 @@ export class LcsDiff {
let bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength);
for (let delta = 1; ; delta++) {
let originalStart = change.originalStart - delta;
let modifiedStart = change.modifiedStart - delta;
const originalStart = change.originalStart - delta;
const modifiedStart = change.modifiedStart - delta;
if (originalStart < originalStop || modifiedStart < modifiedStop) {
break;
@@ -810,7 +868,7 @@ export class LcsDiff {
break;
}
let score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength);
const score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength);
if (score > bestScore) {
bestScore = score;
@@ -826,11 +884,10 @@ export class LcsDiff {
}
private _OriginalIsBoundary(index: number): boolean {
if (index <= 0 || index >= this.OriginalSequence.getLength() - 1) {
if (index <= 0 || index >= this._originalElementsOrHash.length - 1) {
return true;
}
const element = this.OriginalSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index]));
}
private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {
@@ -838,7 +895,7 @@ export class LcsDiff {
return true;
}
if (originalLength > 0) {
let originalEnd = originalStart + originalLength;
const originalEnd = originalStart + originalLength;
if (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) {
return true;
}
@@ -847,11 +904,10 @@ export class LcsDiff {
}
private _ModifiedIsBoundary(index: number): boolean {
if (index <= 0 || index >= this.ModifiedSequence.getLength() - 1) {
if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {
return true;
}
const element = this.ModifiedSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index]));
}
private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {
@@ -859,7 +915,7 @@ export class LcsDiff {
return true;
}
if (modifiedLength > 0) {
let modifiedEnd = modifiedStart + modifiedLength;
const modifiedEnd = modifiedStart + modifiedLength;
if (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) {
return true;
}
@@ -868,8 +924,8 @@ export class LcsDiff {
}
private _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {
let originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
let modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
return (originalScore + modifiedScore);
}
@@ -890,14 +946,14 @@ export class LcsDiff {
// might recurse in the middle of a change thereby splitting it into
// two changes. Here in the combining stage, we detect and fuse those
// changes back together
let result = new Array<DiffChange>(left.length + right.length - 1);
const result = new Array<DiffChange>(left.length + right.length - 1);
MyArray.Copy(left, 0, result, 0, left.length - 1);
result[left.length - 1] = mergedChangeArr[0];
MyArray.Copy(right, 1, result, left.length, right.length - 1);
return result;
} else {
let result = new Array<DiffChange>(left.length + right.length);
const result = new Array<DiffChange>(left.length + right.length);
MyArray.Copy(left, 0, result, 0, left.length);
MyArray.Copy(right, 0, result, left.length, right.length);
@@ -918,9 +974,9 @@ export class LcsDiff {
Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
if (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) {
let originalStart = left.originalStart;
const originalStart = left.originalStart;
let originalLength = left.originalLength;
let modifiedStart = left.modifiedStart;
const modifiedStart = left.modifiedStart;
let modifiedLength = left.modifiedLength;
if (left.originalStart + left.originalLength >= right.originalStart) {
@@ -958,15 +1014,15 @@ export class LcsDiff {
// diagonalsBelow: The number of diagonals below the reference diagonal
// diagonalsAbove: The number of diagonals above the reference diagonal
let diagonalsBelow = diagonalBaseIndex;
let diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;
let diffEven = (numDifferences % 2 === 0);
const diagonalsBelow = diagonalBaseIndex;
const diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;
const diffEven = (numDifferences % 2 === 0);
if (diagonal < 0) {
let lowerBoundEven = (diagonalsBelow % 2 === 0);
const lowerBoundEven = (diagonalsBelow % 2 === 0);
return (diffEven === lowerBoundEven) ? 0 : 1;
} else {
let upperBoundEven = (diagonalsAbove % 2 === 0);
const upperBoundEven = (diagonalsAbove % 2 === 0);
return (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2;
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ function booleanHash(b: boolean, initialHashVal: number): number {
return numberHash(b ? 433 : 863, initialHashVal);
}
function stringHash(s: string, hashVal: number) {
export function stringHash(s: string, hashVal: number) {
hashVal = numberHash(149417, hashVal);
for (let i = 0, length = s.length; i < length; i++) {
hashVal = numberHash(s.charCodeAt(i), hashVal);
+17 -13
View File
@@ -7,23 +7,27 @@ import { equals } from 'vs/base/common/arrays';
import { UriComponents } from 'vs/base/common/uri';
export interface IMarkdownString {
value: string;
isTrusted?: boolean;
readonly value: string;
readonly isTrusted?: boolean;
uris?: { [href: string]: UriComponents };
}
export class MarkdownString implements IMarkdownString {
value: string;
isTrusted?: boolean;
private _value: string;
private _isTrusted: boolean;
constructor(value: string = '') {
this.value = value;
constructor(value: string = '', isTrusted = false) {
this._value = value;
this._isTrusted = isTrusted;
}
get value() { return this._value; }
get isTrusted() { return this._isTrusted; }
appendText(value: string): MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += value
this._value += value
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace('\n', '\n\n');
@@ -31,16 +35,16 @@ export class MarkdownString implements IMarkdownString {
}
appendMarkdown(value: string): MarkdownString {
this.value += value;
this._value += value;
return this;
}
appendCodeblock(langId: string, code: string): MarkdownString {
this.value += '\n```';
this.value += langId;
this.value += '\n';
this.value += code;
this.value += '\n```\n';
this._value += '\n```';
this._value += langId;
this._value += '\n';
this._value += code;
this._value += '\n```\n';
return this;
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ export module Iterator {
};
}
export function fromArray<T>(array: T[], index = 0, length = array.length): Iterator<T> {
export function fromArray<T>(array: ReadonlyArray<T>, index = 0, length = array.length): Iterator<T> {
return {
next(): IteratorResult<T> {
if (index >= length) {
+9 -9
View File
@@ -4,12 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { sep, posix, normalize } from 'vs/base/common/path';
import { sep, posix, normalize, win32 } from 'vs/base/common/path';
import { endsWith, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform';
import { isEqual, basename, relativePath } from 'vs/base/common/resources';
import { CharCode } from 'vs/base/common/charCode';
export interface IWorkspaceFolderProvider {
getWorkspaceFolder(resource: URI): { uri: URI, name?: string } | null;
@@ -44,7 +43,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom
}
if (hasMultipleRoots) {
const rootName = (baseResource && baseResource.name) ? baseResource.name : basename(baseResource.uri);
const rootName = baseResource.name ? baseResource.name : basename(baseResource.uri);
pathLabel = pathLabel ? (rootName + ' • ' + pathLabel) : rootName; // always show root basename if there are multiple
}
@@ -388,11 +387,12 @@ export function unmnemonicLabel(label: string): string {
* Splits a path in name and parent path, supporting both '/' and '\'
*/
export function splitName(fullPath: string): { name: string, parentPath: string } {
for (let i = fullPath.length - 1; i >= 1; i--) {
const code = fullPath.charCodeAt(i);
if (code === CharCode.Slash || code === CharCode.Backslash) {
return { parentPath: fullPath.substr(0, i), name: fullPath.substr(i + 1) };
}
const p = fullPath.indexOf('/') !== -1 ? posix : win32;
const name = p.basename(fullPath);
const parentPath = p.dirname(fullPath);
if (name.length) {
return { name, parentPath };
}
return { parentPath: '', name: fullPath };
// only the root segment
return { name: parentPath, parentPath: '' };
}
+65
View File
@@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* A value that is resolved synchronously when it is first needed.
*/
export interface Lazy<T> {
hasValue(): boolean;
getValue(): T;
map<R>(f: (x: T) => R): Lazy<R>;
}
export class Lazy<T> {
private _didRun: boolean = false;
private _value?: T;
private _error: any;
constructor(
private readonly executor: () => T,
) { }
/**
* True if the lazy value has been resolved.
*/
hasValue() { return this._didRun; }
/**
* Get the wrapped value.
*
* This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only
* resolved once. `getValue` will re-throw exceptions that are hit while resolving the value
*/
getValue(): T {
if (!this._didRun) {
try {
this._value = this.executor();
} catch (err) {
this._error = err;
} finally {
this._didRun = true;
}
}
if (this._error) {
throw this._error;
}
return this._value!;
}
/**
* Create a new lazy value that is the result of applying `f` to the wrapped value.
*
* This does not force the evaluation of the current lazy value.
*/
map<R>(f: (x: T) => R): Lazy<R> {
return new Lazy<R>(() => f(this.getValue()));
}
}
+1 -1
View File
@@ -138,7 +138,7 @@ export class DisposableStore implements IDisposable {
export abstract class Disposable implements IDisposable {
static None = Object.freeze<IDisposable>({ dispose() { } });
static readonly None = Object.freeze<IDisposable>({ dispose() { } });
private readonly _store = new DisposableStore();
+3 -1
View File
@@ -117,6 +117,8 @@ export class PathIterator implements IKeyIterator {
private _from!: number;
private _to!: number;
constructor(private _splitOnBackslash: boolean = true) { }
reset(key: string): this {
this._value = key.replace(/\\$|\/$/, '');
this._from = 0;
@@ -134,7 +136,7 @@ export class PathIterator implements IKeyIterator {
let justSeps = true;
for (; this._to < this._value.length; this._to++) {
const ch = this._value.charCodeAt(this._to);
if (ch === CharCode.Slash || ch === CharCode.Backslash) {
if (ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash) {
if (justSeps) {
this._from++;
} else {
+16 -20
View File
@@ -56,53 +56,49 @@ export namespace Schemas {
}
class RemoteAuthoritiesImpl {
private readonly _hosts: { [authority: string]: string; };
private readonly _ports: { [authority: string]: number; };
private readonly _connectionTokens: { [authority: string]: string; };
private _preferredWebSchema: 'http' | 'https';
private _delegate: ((uri: URI) => URI) | null;
private readonly _hosts: { [authority: string]: string | undefined; } = Object.create(null);
private readonly _ports: { [authority: string]: number | undefined; } = Object.create(null);
private readonly _connectionTokens: { [authority: string]: string | undefined; } = Object.create(null);
private _preferredWebSchema: 'http' | 'https' = 'http';
private _delegate: ((uri: URI) => URI) | null = null;
constructor() {
this._hosts = Object.create(null);
this._ports = Object.create(null);
this._connectionTokens = Object.create(null);
this._preferredWebSchema = 'http';
this._delegate = null;
}
public setPreferredWebSchema(schema: 'http' | 'https') {
setPreferredWebSchema(schema: 'http' | 'https') {
this._preferredWebSchema = schema;
}
public setDelegate(delegate: (uri: URI) => URI): void {
setDelegate(delegate: (uri: URI) => URI): void {
this._delegate = delegate;
}
public set(authority: string, host: string, port: number): void {
set(authority: string, host: string, port: number): void {
this._hosts[authority] = host;
this._ports[authority] = port;
}
public setConnectionToken(authority: string, connectionToken: string): void {
setConnectionToken(authority: string, connectionToken: string): void {
this._connectionTokens[authority] = connectionToken;
}
public rewrite(uri: URI): URI {
rewrite(uri: URI): URI {
if (this._delegate) {
return this._delegate(uri);
}
const authority = uri.authority;
let host = this._hosts[authority];
if (host.indexOf(':') !== -1) {
if (host && host.indexOf(':') !== -1) {
host = `[${host}]`;
}
const port = this._ports[authority];
const connectionToken = this._connectionTokens[authority];
let query = `path=${encodeURIComponent(uri.path)}`;
if (typeof connectionToken === 'string') {
query += `&tkn=${encodeURIComponent(connectionToken)}`;
}
return URI.from({
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
authority: `${host}:${port}`,
path: `/vscode-remote-resource`,
query: `path=${encodeURIComponent(uri.path)}&tkn=${encodeURIComponent(connectionToken)}`
query
});
}
}
-126
View File
@@ -1,126 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { matchesFuzzy, IMatch } from 'vs/base/common/filters';
import { ltrim } from 'vs/base/common/strings';
const octiconStartMarker = '$(';
export interface IParsedOcticons {
text: string;
octiconOffsets?: number[];
}
export function parseOcticons(text: string): IParsedOcticons {
const firstOcticonIndex = text.indexOf(octiconStartMarker);
if (firstOcticonIndex === -1) {
return { text }; // return early if the word does not include an octicon
}
return doParseOcticons(text, firstOcticonIndex);
}
function doParseOcticons(text: string, firstOcticonIndex: number): IParsedOcticons {
const octiconOffsets: number[] = [];
let textWithoutOcticons: string = '';
function appendChars(chars: string) {
if (chars) {
textWithoutOcticons += chars;
for (const _ of chars) {
octiconOffsets.push(octiconsOffset); // make sure to fill in octicon offsets
}
}
}
let currentOcticonStart = -1;
let currentOcticonValue: string = '';
let octiconsOffset = 0;
let char: string;
let nextChar: string;
let offset = firstOcticonIndex;
const length = text.length;
// Append all characters until the first octicon
appendChars(text.substr(0, firstOcticonIndex));
// example: $(file-symlink-file) my cool $(other-octicon) entry
while (offset < length) {
char = text[offset];
nextChar = text[offset + 1];
// beginning of octicon: some value $( <--
if (char === octiconStartMarker[0] && nextChar === octiconStartMarker[1]) {
currentOcticonStart = offset;
// if we had a previous potential octicon value without
// the closing ')', it was actually not an octicon and
// so we have to add it to the actual value
appendChars(currentOcticonValue);
currentOcticonValue = octiconStartMarker;
offset++; // jump over '('
}
// end of octicon: some value $(some-octicon) <--
else if (char === ')' && currentOcticonStart !== -1) {
const currentOcticonLength = offset - currentOcticonStart + 1; // +1 to include the closing ')'
octiconsOffset += currentOcticonLength;
currentOcticonStart = -1;
currentOcticonValue = '';
}
// within octicon
else if (currentOcticonStart !== -1) {
currentOcticonValue += char;
}
// any value outside of octicons
else {
appendChars(char);
}
offset++;
}
// if we had a previous potential octicon value without
// the closing ')', it was actually not an octicon and
// so we have to add it to the actual value
appendChars(currentOcticonValue);
return { text: textWithoutOcticons, octiconOffsets };
}
export function matchesFuzzyOcticonAware(query: string, target: IParsedOcticons, enableSeparateSubstringMatching = false): IMatch[] | null {
const { text, octiconOffsets } = target;
// Return early if there are no octicon markers in the word to match against
if (!octiconOffsets || octiconOffsets.length === 0) {
return matchesFuzzy(query, text, enableSeparateSubstringMatching);
}
// Trim the word to match against because it could have leading
// whitespace now if the word started with an octicon
const wordToMatchAgainstWithoutOcticonsTrimmed = ltrim(text, ' ');
const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutOcticonsTrimmed.length;
// match on value without octicons
const matches = matchesFuzzy(query, wordToMatchAgainstWithoutOcticonsTrimmed, enableSeparateSubstringMatching);
// Map matches back to offsets with octicons and trimming
if (matches) {
for (const match of matches) {
const octiconOffset = octiconOffsets[match.start + leadingWhitespaceOffset] /* octicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
match.start += octiconOffset;
match.end += octiconOffset;
}
}
return matches;
}
+2 -2
View File
@@ -169,7 +169,7 @@ function _format(sep: string, pathObject: ParsedPath) {
return dir + sep + base;
}
interface ParsedPath {
export interface ParsedPath {
root: string;
dir: string;
base: string;
@@ -177,7 +177,7 @@ interface ParsedPath {
name: string;
}
interface IPath {
export interface IPath {
normalize(path: string): string;
isAbsolute(path: string): boolean;
join(...paths: string[]): string;
+28
View File
@@ -164,6 +164,34 @@ export const setImmediate: ISetImmediate = (function defineSetImmediate() {
if (globals.setImmediate) {
return globals.setImmediate.bind(globals);
}
if (typeof globals.postMessage === 'function' && !globals.importScripts) {
interface IQueueElement {
id: number;
callback: () => void;
}
let pending: IQueueElement[] = [];
globals.addEventListener('message', (e: MessageEvent) => {
if (e.data && e.data.vscodeSetImmediateId) {
for (let i = 0, len = pending.length; i < len; i++) {
const candidate = pending[i];
if (candidate.id === e.data.vscodeSetImmediateId) {
pending.splice(i, 1);
candidate.callback();
return;
}
}
}
});
let lastId = 0;
return (callback: () => void) => {
const myId = ++lastId;
pending.push({
id: myId,
callback: callback
});
globals.postMessage({ vscodeSetImmediateId: myId });
};
}
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
return process.nextTick.bind(process);
}
+88 -92
View File
@@ -9,93 +9,77 @@ import { Iterator } from 'vs/base/common/iterator';
import { relativePath, joinPath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { mapValues } from 'vs/base/common/collections';
import { PathIterator } from 'vs/base/common/map';
export interface ILeafNode<T, C = void> {
export interface IResourceNode<T, C = void> {
readonly uri: URI;
readonly relativePath: string;
readonly name: string;
readonly element: T;
readonly element: T | undefined;
readonly children: Iterator<IResourceNode<T, C>>;
readonly childrenCount: number;
readonly parent: IResourceNode<T, C> | undefined;
readonly context: C;
get(childName: string): IResourceNode<T, C> | undefined;
}
export interface IBranchNode<T, C = void> {
readonly uri: URI;
readonly relativePath: string;
readonly name: string;
readonly size: number;
readonly children: Iterator<INode<T, C>>;
readonly parent: IBranchNode<T, C> | undefined;
readonly context: C;
get(childName: string): INode<T, C> | undefined;
}
class Node<T, C> implements IResourceNode<T, C> {
export type INode<T, C> = IBranchNode<T, C> | ILeafNode<T, C>;
private _children = new Map<string, Node<T, C>>();
// Internals
class Node<C> {
@memoize
get name(): string { return paths.posix.basename(this.relativePath); }
constructor(readonly uri: URI, readonly relativePath: string, readonly context: C) { }
}
class BranchNode<T, C> extends Node<C> implements IBranchNode<T, C> {
private _children = new Map<string, BranchNode<T, C> | LeafNode<T, C>>();
get size(): number {
get childrenCount(): number {
return this._children.size;
}
get children(): Iterator<BranchNode<T, C> | LeafNode<T, C>> {
get children(): Iterator<Node<T, C>> {
return Iterator.fromArray(mapValues(this._children));
}
constructor(uri: URI, relativePath: string, context: C, readonly parent: IBranchNode<T, C> | undefined = undefined) {
super(uri, relativePath, context);
@memoize
get name(): string {
return paths.posix.basename(this.relativePath);
}
get(path: string): BranchNode<T, C> | LeafNode<T, C> | undefined {
constructor(
readonly uri: URI,
readonly relativePath: string,
readonly context: C,
public element: T | undefined = undefined,
readonly parent: IResourceNode<T, C> | undefined = undefined
) { }
get(path: string): Node<T, C> | undefined {
return this._children.get(path);
}
set(path: string, child: BranchNode<T, C> | LeafNode<T, C>): void {
set(path: string, child: Node<T, C>): void {
this._children.set(path, child);
}
delete(path: string): void {
this._children.delete(path);
}
}
class LeafNode<T, C> extends Node<C> implements ILeafNode<T, C> {
constructor(uri: URI, path: string, context: C, readonly element: T) {
super(uri, path, context);
clear(): void {
this._children.clear();
}
}
function collect<T, C>(node: INode<T, C>, result: T[]): T[] {
if (ResourceTree.isBranchNode(node)) {
Iterator.forEach(node.children, child => collect(child, result));
} else {
function collect<T, C>(node: IResourceNode<T, C>, result: T[]): T[] {
if (typeof node.element !== 'undefined') {
result.push(node.element);
}
Iterator.forEach(node.children, child => collect(child, result));
return result;
}
export class ResourceTree<T extends NonNullable<any>, C> {
readonly root: BranchNode<T, C>;
readonly root: Node<T, C>;
static isBranchNode<T, C>(obj: any): obj is IBranchNode<T, C> {
return obj instanceof BranchNode;
}
static getRoot<T, C>(node: IBranchNode<T, C>): IBranchNode<T, C> {
static getRoot<T, C>(node: IResourceNode<T, C>): IResourceNode<T, C> {
while (node.parent) {
node = node.parent;
}
@@ -103,89 +87,101 @@ export class ResourceTree<T extends NonNullable<any>, C> {
return node;
}
static collect<T, C>(node: INode<T, C>): T[] {
static collect<T, C>(node: IResourceNode<T, C>): T[] {
return collect(node, []);
}
static isResourceNode<T, C>(obj: any): obj is IResourceNode<T, C> {
return obj instanceof Node;
}
constructor(context: C, rootURI: URI = URI.file('/')) {
this.root = new BranchNode(rootURI, '', context);
this.root = new Node(rootURI, '', context);
}
add(uri: URI, element: T): void {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const parts = key.split(/[\\\/]/).filter(p => !!p);
const iterator = new PathIterator(false).reset(key);
let node = this.root;
let path = '';
for (let i = 0; i < parts.length; i++) {
const name = parts[i];
while (true) {
const name = iterator.value();
path = path + '/' + name;
let child = node.get(name);
if (!child) {
if (i < parts.length - 1) {
child = new BranchNode(joinPath(this.root.uri, path), path, this.root.context, node);
node.set(name, child);
} else {
child = new LeafNode(uri, path, this.root.context, element);
node.set(name, child);
return;
}
}
child = new Node(
joinPath(this.root.uri, path),
path,
this.root.context,
iterator.hasNext() ? undefined : element,
node
);
if (!(child instanceof BranchNode)) {
if (i < parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override leaf with branch.');
}
// replace
node.set(name, new LeafNode(uri, path, this.root.context, element));
return;
} else if (i === parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override branch with leaf.');
node.set(name, child);
} else if (!iterator.hasNext()) {
child.element = element;
}
node = child;
if (!iterator.hasNext()) {
return;
}
iterator.next();
}
}
delete(uri: URI): T | undefined {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const parts = key.split(/[\\\/]/).filter(p => !!p);
return this._delete(this.root, parts, 0);
const iterator = new PathIterator(false).reset(key);
return this._delete(this.root, iterator);
}
private _delete(node: BranchNode<T, C>, parts: string[], index: number): T | undefined {
const name = parts[index];
private _delete(node: Node<T, C>, iterator: PathIterator): T | undefined {
const name = iterator.value();
const child = node.get(name);
if (!child) {
return undefined;
}
// not at end
if (index < parts.length - 1) {
if (child instanceof BranchNode) {
const result = this._delete(child, parts, index + 1);
if (iterator.hasNext()) {
const result = this._delete(child, iterator.next());
if (typeof result !== 'undefined' && child.size === 0) {
node.delete(name);
}
return result;
} else {
throw new Error('Inconsistent tree: Expected a branch, found a leaf instead.');
if (typeof result !== 'undefined' && child.childrenCount === 0) {
node.delete(name);
}
}
//at end
if (child instanceof BranchNode) {
// TODO: maybe we can allow this
throw new Error('Inconsistent tree: Expected a leaf, found a branch instead.');
return result;
}
node.delete(name);
return child.element;
}
clear(): void {
this.root.clear();
}
getNode(uri: URI): IResourceNode<T, C> | undefined {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const iterator = new PathIterator(false).reset(key);
let node = this.root;
while (true) {
const name = iterator.value();
const child = node.get(name);
if (!child || !iterator.hasNext()) {
return child;
}
node = child;
iterator.next();
}
}
}
+8 -9
View File
@@ -7,20 +7,19 @@ import * as strings from './strings';
export function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string {
if (matches && (matches[0] !== '')) {
const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');
const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');
if (containsHyphens && !containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
} else if (!containsHyphens && containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');
}
if (matches[0].toUpperCase() === matches[0]) {
return pattern.toUpperCase();
} else if (matches[0].toLowerCase() === matches[0]) {
return pattern.toLowerCase();
} else if (strings.containsUppercaseCharacter(matches[0][0])) {
const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');
const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');
if (containsHyphens && !containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
} else if (!containsHyphens && containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');
} else {
return pattern[0].toUpperCase() + pattern.substr(1);
}
return pattern[0].toUpperCase() + pattern.substr(1);
} else {
// we don't understand its pattern yet.
return pattern;
+1 -12
View File
@@ -350,21 +350,10 @@ function isAsciiLetter(code: number): boolean {
}
export function equalsIgnoreCase(a: string, b: string): boolean {
const len1 = a ? a.length : 0;
const len2 = b ? b.length : 0;
if (len1 !== len2) {
return false;
}
return doEqualsIgnoreCase(a, b);
return a.length === b.length && doEqualsIgnoreCase(a, b);
}
function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {
if (typeof a !== 'string' || typeof b !== 'string') {
return false;
}
for (let i = 0; i < stopAt; i++) {
const codeA = a.charCodeAt(i);
const codeB = b.charCodeAt(i);
+33
View File
@@ -93,6 +93,39 @@ export function isUndefinedOrNull(obj: any): obj is undefined | null {
return isUndefined(obj) || obj === null;
}
/**
* Asserts that the argument passed in is neither undefined nor null.
*/
export function assertIsDefined<T>(arg: T | null | undefined): T {
if (isUndefinedOrNull(arg)) {
throw new Error('Assertion Failed: argument is undefined or null');
}
return arg;
}
/**
* Asserts that each argument passed in is neither undefined nor null.
*/
export function assertAllDefined<T1, T2>(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2];
export function assertAllDefined<T1, T2, T3>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3];
export function assertAllDefined<T1, T2, T3, T4>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4];
export function assertAllDefined(...args: (unknown | null | undefined)[]): unknown[] {
const result = [];
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (isUndefinedOrNull(arg)) {
throw new Error(`Assertion Failed: argument at index ${i} is undefined or null`);
}
result.push(arg);
}
return result;
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
@@ -3,32 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export class Uint8Matrix {
private readonly _data: Uint8Array;
public readonly rows: number;
public readonly cols: number;
constructor(rows: number, cols: number, defaultValue: number) {
const data = new Uint8Array(rows * cols);
for (let i = 0, len = rows * cols; i < len; i++) {
data[i] = defaultValue;
}
this._data = data;
this.rows = rows;
this.cols = cols;
}
public get(row: number, col: number): number {
return this._data[row * this.cols + col];
}
public set(row: number, col: number, value: number): void {
this._data[row * this.cols + col] = value;
}
}
export const enum Constants {
/**
* MAX SMI (SMall Integer) as defined in v8.
+13 -35
View File
@@ -10,26 +10,11 @@ const _schemePattern = /^\w[\w\d+.-]*$/;
const _singleSlashStart = /^\//;
const _doubleSlashStart = /^\/\//;
let _throwOnMissingSchema: boolean = true;
/**
* @internal
*/
export function setUriThrowOnMissingScheme(value: boolean): boolean {
const old = _throwOnMissingSchema;
_throwOnMissingSchema = value;
return old;
}
function _validateUri(ret: URI, _strict?: boolean): void {
function _validateUri(ret: URI): void {
// scheme, must be set
if (!ret.scheme) {
if (_strict || _throwOnMissingSchema) {
throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
} else {
console.warn(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
}
throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
}
// scheme, https://tools.ietf.org/html/rfc3986#section-3.1
@@ -56,14 +41,8 @@ function _validateUri(ret: URI, _strict?: boolean): void {
}
}
// for a while we allowed uris *without* schemes and this is the migration
// for them, e.g. an uri without scheme and without strict-mode warns and falls
// back to the file-scheme. that should cause the least carnage and still be a
// clear warning
function _schemeFix(scheme: string, _strict: boolean): string {
if (_strict || _throwOnMissingSchema) {
return scheme || _empty;
}
// graceful behaviour when scheme is missing: fallback to using 'file'-scheme
function _schemeFix(scheme: string): string {
if (!scheme) {
console.trace('BAD uri lacks scheme, falling back to file-scheme.');
scheme = 'file';
@@ -159,7 +138,7 @@ export class URI implements UriComponents {
/**
* @internal
*/
protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean);
protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string);
/**
* @internal
@@ -169,7 +148,7 @@ export class URI implements UriComponents {
/**
* @internal
*/
protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string, _strict: boolean = false) {
protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string) {
if (typeof schemeOrData === 'object') {
this.scheme = schemeOrData.scheme || _empty;
@@ -181,13 +160,13 @@ export class URI implements UriComponents {
// that creates uri components.
// _validateUri(this);
} else {
this.scheme = _schemeFix(schemeOrData, _strict);
this.scheme = _schemeFix(schemeOrData);
this.authority = authority || _empty;
this.path = _referenceResolution(this.scheme, path || _empty);
this.query = query || _empty;
this.fragment = fragment || _empty;
_validateUri(this, _strict);
_validateUri(this);
}
}
@@ -226,7 +205,7 @@ export class URI implements UriComponents {
// ---- modify to new -------------------------
with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null; }): URI {
if (!change) {
return this;
@@ -279,7 +258,7 @@ export class URI implements UriComponents {
*
* @param value A string which represents an URI (see `URI#toString`).
*/
static parse(value: string, _strict: boolean = false): URI {
static parse(value: string): URI {
const match = _regexp.exec(value);
if (!match) {
return new _URI(_empty, _empty, _empty, _empty, _empty);
@@ -289,8 +268,7 @@ export class URI implements UriComponents {
decodeURIComponent(match[4] || _empty),
decodeURIComponent(match[5] || _empty),
decodeURIComponent(match[7] || _empty),
decodeURIComponent(match[9] || _empty),
_strict
decodeURIComponent(match[9] || _empty)
);
}
@@ -342,7 +320,7 @@ export class URI implements UriComponents {
return new _URI('file', authority, path, _empty, _empty);
}
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string; }): URI {
return new _URI(
components.scheme,
components.authority,
@@ -467,7 +445,7 @@ class _URI extends URI {
}
// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
const encodeTable: { [ch: number]: string } = {
const encodeTable: { [ch: number]: string; } = {
[CharCode.Colon]: '%3A', // gen-delims
[CharCode.Slash]: '%2F',
[CharCode.QuestionMark]: '%3F',
+5 -1
View File
@@ -122,7 +122,11 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
// detection. thus, wrap up starting the stream even
// without all the data to get things going
else {
this._startDecodeStream(() => this.decodeStream!.end(callback));
this._startDecodeStream(() => {
if (this.decodeStream) {
this.decodeStream.end(callback);
}
});
}
}
};
+1
View File
@@ -9,6 +9,7 @@ export interface NLSConfiguration {
[key: string]: string;
};
pseudo?: boolean;
_languagePackSupport?: boolean;
}
export interface InternalNLSConfiguration extends NLSConfiguration {
+5 -11
View File
@@ -11,21 +11,15 @@ const cmdline = {
unix: '/sbin/ifconfig -a || /sbin/ip link'
};
const invalidMacAddresses = [
const invalidMacAddresses = new Set([
'00:00:00:00:00:00',
'ff:ff:ff:ff:ff:ff',
'ac:de:48:00:11:22'
];
]);
function validateMacAddress(candidate: string): boolean {
let tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
for (let invalidMacAddress of invalidMacAddresses) {
if (invalidMacAddress === tempCandidate) {
return false;
}
}
return true;
const tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
return !invalidMacAddresses.has(tempCandidate);
}
export function getMac(): Promise<string> {
@@ -66,4 +60,4 @@ function doGetMac(): Promise<string> {
reject(err);
}
});
}
}
+15 -1
View File
@@ -138,6 +138,20 @@ export async function readdir(path: string): Promise<string[]> {
return handleDirectoryChildren(await promisify(fs.readdir)(path));
}
export async function readdirWithFileTypes(path: string): Promise<fs.Dirent[]> {
const children = await promisify(fs.readdir)(path, { withFileTypes: true });
// Mac: uses NFD unicode form on disk, but we want NFC
// See also https://github.com/nodejs/node/issues/2165
if (platform.isMacintosh) {
for (const child of children) {
child.name = normalizeNFC(child.name);
}
}
return children;
}
export function readdirSync(path: string): string[] {
return handleDirectoryChildren(fs.readdirSync(path));
}
@@ -679,4 +693,4 @@ const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB
const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB
export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE;
export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE;
export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE;
+53 -25
View File
@@ -40,7 +40,7 @@ function getWindowsCode(status: number): TerminateResponseCode {
}
}
export function terminateProcess(process: cp.ChildProcess, cwd?: string): TerminateResponse {
function terminateProcess(process: cp.ChildProcess, cwd?: string): Promise<TerminateResponse> {
if (Platform.isWindows) {
try {
const options: any = {
@@ -49,24 +49,41 @@ export function terminateProcess(process: cp.ChildProcess, cwd?: string): Termin
if (cwd) {
options.cwd = cwd;
}
cp.execFileSync('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options);
const killProcess = cp.execFile('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options);
return new Promise((resolve, reject) => {
killProcess.once('error', (err) => {
resolve({ success: false, error: err });
});
killProcess.once('exit', (code, signal) => {
if (code === 0) {
resolve({ success: true });
} else {
resolve({ success: false, code: code !== null ? code : TerminateResponseCode.Unknown });
}
});
});
} catch (err) {
return { success: false, error: err, code: err.status ? getWindowsCode(err.status) : TerminateResponseCode.Unknown };
return Promise.resolve({ success: false, error: err, code: err.status ? getWindowsCode(err.status) : TerminateResponseCode.Unknown });
}
} else if (Platform.isLinux || Platform.isMacintosh) {
try {
const cmd = getPathFromAmdModule(require, 'vs/base/node/terminateProcess.sh');
const result = cp.spawnSync(cmd, [process.pid.toString()]);
if (result.error) {
return { success: false, error: result.error };
}
return new Promise((resolve, reject) => {
cp.execFile(cmd, [process.pid.toString()], { encoding: 'utf8', shell: true } as cp.ExecFileOptions, (err, stdout, stderr) => {
if (err) {
resolve({ success: false, error: err });
} else {
resolve({ success: true });
}
});
});
} catch (err) {
return { success: false, error: err };
return Promise.resolve({ success: false, error: err });
}
} else {
process.kill('SIGKILL');
}
return { success: true };
return Promise.resolve({ success: true });
}
export function getWindowsShell(): string {
@@ -122,6 +139,7 @@ export abstract class AbstractProcess<TProgressData> {
}
this.childProcess = null;
this.childProcessPromise = null;
this.terminateRequested = false;
if (this.options.env) {
@@ -288,11 +306,12 @@ export abstract class AbstractProcess<TProgressData> {
}
return this.childProcessPromise.then((childProcess) => {
this.terminateRequested = true;
const result = terminateProcess(childProcess, this.options.cwd);
if (result.success) {
this.childProcess = null;
}
return result;
return terminateProcess(childProcess, this.options.cwd).then(response => {
if (response.success) {
this.childProcess = null;
}
return response;
});
}, (err) => {
return { success: true };
});
@@ -316,13 +335,16 @@ export abstract class AbstractProcess<TProgressData> {
export class LineProcess extends AbstractProcess<LineData> {
private stdoutLineDecoder: LineDecoder;
private stderrLineDecoder: LineDecoder;
private stdoutLineDecoder: LineDecoder | null;
private stderrLineDecoder: LineDecoder | null;
public constructor(executable: Executable);
public constructor(cmd: string, args: string[], shell: boolean, options: CommandOptions);
public constructor(arg1: string | Executable, arg2?: string[], arg3?: boolean | ForkOptions, arg4?: CommandOptions) {
super(<any>arg1, arg2, <any>arg3, arg4);
this.stdoutLineDecoder = null;
this.stderrLineDecoder = null;
}
protected handleExec(cc: ValueCallback<SuccessData>, pp: ProgressCallback<LineData>, error: Error, stdout: Buffer, stderr: Buffer) {
@@ -341,24 +363,30 @@ export class LineProcess extends AbstractProcess<LineData> {
}
protected handleSpawn(childProcess: cp.ChildProcess, cc: ValueCallback<SuccessData>, pp: ProgressCallback<LineData>, ee: ErrorCallback, sync: boolean): void {
this.stdoutLineDecoder = new LineDecoder();
this.stderrLineDecoder = new LineDecoder();
const stdoutLineDecoder = new LineDecoder();
const stderrLineDecoder = new LineDecoder();
childProcess.stdout.on('data', (data: Buffer) => {
const lines = this.stdoutLineDecoder.write(data);
const lines = stdoutLineDecoder.write(data);
lines.forEach(line => pp({ line: line, source: Source.stdout }));
});
childProcess.stderr.on('data', (data: Buffer) => {
const lines = this.stderrLineDecoder.write(data);
const lines = stderrLineDecoder.write(data);
lines.forEach(line => pp({ line: line, source: Source.stderr }));
});
this.stdoutLineDecoder = stdoutLineDecoder;
this.stderrLineDecoder = stderrLineDecoder;
}
protected handleClose(data: any, cc: ValueCallback<SuccessData>, pp: ProgressCallback<LineData>, ee: ErrorCallback): void {
[this.stdoutLineDecoder.end(), this.stderrLineDecoder.end()].forEach((line, index) => {
if (line) {
pp({ line: line, source: index === 0 ? Source.stdout : Source.stderr });
}
});
const stdoutLine = this.stdoutLineDecoder ? this.stdoutLineDecoder.end() : null;
if (stdoutLine) {
pp({ line: stdoutLine, source: Source.stdout });
}
const stderrLine = this.stderrLineDecoder ? this.stderrLineDecoder.end() : null;
if (stderrLine) {
pp({ line: stderrLine, source: Source.stderr });
}
}
}
+1 -1
View File
@@ -156,7 +156,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
const stream = openZipStream(zipfile, entry);
const mode = modeFromEntry(entry);
last = createCancelablePromise(token => throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options, token).then(() => readNextEntry(token)))).then(null!, e));
last = createCancelablePromise(token => throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options, token).then(() => readNextEntry(token)))).then(null, e));
});
});
}
@@ -28,7 +28,7 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions): void
ipcRenderer.removeListener(onClickChannel, onClickChannelHandler);
if (options && options.onHide) {
if (options?.onHide) {
options.onHide();
}
});
@@ -55,4 +55,4 @@ function createItem(item: IContextMenuItem, processedItems: IContextMenuItem[]):
}
return serializableItem;
}
}
@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Menu, MenuItem, BrowserWindow, ipcMain, Event as IpcMainEvent } from 'electron';
import { Menu, MenuItem, BrowserWindow, ipcMain, IpcMainEvent } from 'electron';
import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_CHANNEL, IPopupOptions } from 'vs/base/parts/contextmenu/common/contextmenu';
export function registerContextMenuListener(): void {
-1
View File
@@ -8,7 +8,6 @@ import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/li
import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
/**
@@ -24,7 +24,7 @@ function createScopedOnMessageEvent(senderId: number, eventName: string): Event<
export class Server extends IPCServer {
private static Clients = new Map<number, IDisposable>();
private static readonly Clients = new Map<number, IDisposable>();
private static getOnDidClientConnect(): Event<ClientConnectionEvent> {
const onHello = Event.fromNodeEventEmitter<WebContents>(ipcMain, 'ipc:hello', ({ sender }) => sender);
@@ -53,7 +53,7 @@ export const QuickOpenItemAccessor = new QuickOpenItemAccessorClass();
export class QuickOpenEntry {
private id: string;
private labelHighlights: IHighlight[];
private labelHighlights?: IHighlight[];
private descriptionHighlights?: IHighlight[];
private detailHighlights?: IHighlight[];
private hidden: boolean | undefined;
@@ -160,7 +160,7 @@ export class QuickOpenEntry {
/**
* Allows to set highlight ranges that should show up for the entry label and optionally description if set.
*/
setHighlights(labelHighlights: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
this.labelHighlights = labelHighlights;
this.descriptionHighlights = descriptionHighlights;
this.detailHighlights = detailHighlights;
@@ -169,7 +169,7 @@ export class QuickOpenEntry {
/**
* Allows to return highlight ranges that should show up for the entry label and description.
*/
getHighlights(): [IHighlight[] /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] {
getHighlights(): [IHighlight[] | undefined /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] {
return [this.labelHighlights, this.descriptionHighlights, this.detailHighlights];
}
@@ -260,7 +260,7 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
return this.entry;
}
getHighlights(): [IHighlight[], IHighlight[] | undefined, IHighlight[] | undefined] {
getHighlights(): [IHighlight[] | undefined, IHighlight[] | undefined, IHighlight[] | undefined] {
return this.entry ? this.entry.getHighlights() : super.getHighlights();
}
@@ -268,7 +268,7 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
return this.entry ? this.entry.isHidden() : super.isHidden();
}
setHighlights(labelHighlights: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
this.entry ? this.entry.setHighlights(labelHighlights, descriptionHighlights, detailHighlights) : super.setHighlights(labelHighlights, descriptionHighlights, detailHighlights);
}
@@ -351,7 +351,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
row1.appendChild(icon);
// Label
const label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportOcticons: true });
const label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportCodicons: true });
// Keybinding
const keybindingContainer = document.createElement('span');
@@ -434,7 +434,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
}
} else {
DOM.removeClass(groupData.container, 'results-group-separator');
groupData.container.style.borderTopColor = null;
groupData.container.style.borderTopColor = '';
}
// Group Label
@@ -99,25 +99,40 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
private isDisposed: boolean;
private options: IQuickOpenOptions;
// @ts-ignore (legacy widget - to be replaced with quick input)
private element: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private tree: ITree;
// @ts-ignore (legacy widget - to be replaced with quick input)
private inputBox: InputBox;
// @ts-ignore (legacy widget - to be replaced with quick input)
private inputContainer: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private helpText: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private resultCount: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private treeContainer: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private progressBar: ProgressBar;
// @ts-ignore (legacy widget - to be replaced with quick input)
private visible: boolean;
// @ts-ignore (legacy widget - to be replaced with quick input)
private isLoosingFocus: boolean;
private callbacks: IQuickOpenCallbacks;
private quickNavigateConfiguration: IQuickNavigateConfiguration | undefined;
private container: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private treeElement: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private inputElement: HTMLElement;
// @ts-ignore (legacy widget - to be replaced with quick input)
private layoutDimensions: DOM.Dimension;
private model: IModel<any> | null;
private inputChangingTimeoutHandle: any;
// @ts-ignore (legacy widget - to be replaced with quick input)
private styles: IQuickOpenStyles;
// @ts-ignore (legacy widget - to be replaced with quick input)
private renderer: Renderer;
constructor(container: HTMLElement, callbacks: IQuickOpenCallbacks, options: IQuickOpenOptions) {
@@ -381,16 +396,16 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
protected applyStyles(): void {
if (this.element) {
const foreground = this.styles.foreground ? this.styles.foreground.toString() : null;
const background = this.styles.background ? this.styles.background.toString() : null;
const borderColor = this.styles.borderColor ? this.styles.borderColor.toString() : null;
const widgetShadow = this.styles.widgetShadow ? this.styles.widgetShadow.toString() : null;
const background = this.styles.background ? this.styles.background.toString() : '';
const borderColor = this.styles.borderColor ? this.styles.borderColor.toString() : '';
const widgetShadow = this.styles.widgetShadow ? this.styles.widgetShadow.toString() : '';
this.element.style.color = foreground;
this.element.style.backgroundColor = background;
this.element.style.borderColor = borderColor;
this.element.style.borderWidth = borderColor ? '1px' : null;
this.element.style.borderStyle = borderColor ? 'solid' : null;
this.element.style.boxShadow = widgetShadow ? `0 5px 8px ${widgetShadow}` : null;
this.element.style.borderWidth = borderColor ? '1px' : '';
this.element.style.borderStyle = borderColor ? 'solid' : '';
this.element.style.boxShadow = widgetShadow ? `0 5px 8px ${widgetShadow}` : '';
}
if (this.progressBar) {
+11 -9
View File
@@ -32,12 +32,12 @@ export interface ISQLiteStorageDatabaseLoggingOptions {
export class SQLiteStorageDatabase implements IStorageDatabase {
static IN_MEMORY_PATH = ':memory:';
static readonly IN_MEMORY_PATH = ':memory:';
get onDidChangeItemsExternal(): Event<IStorageItemsChangeEvent> { return Event.None; } // since we are the only client, there can be no external changes
private static BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY
private static MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement
private static readonly BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY
private static readonly MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement
private path: string;
private name: string;
@@ -82,16 +82,18 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
}
return this.transaction(connection, () => {
const toInsert = request.insert;
const toDelete = request.delete;
// INSERT
if (request.insert && request.insert.size > 0) {
if (toInsert && toInsert.size > 0) {
const keysValuesChunks: (string[])[] = [];
keysValuesChunks.push([]); // seed with initial empty chunk
// Split key/values into chunks of SQLiteStorageDatabase.MAX_HOST_PARAMETERS
// so that we can efficiently run the INSERT with as many HOST parameters as possible
let currentChunkIndex = 0;
request.insert.forEach((value, key) => {
toInsert.forEach((value, key) => {
let keyValueChunk = keysValuesChunks[currentChunkIndex];
if (keyValueChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) {
@@ -107,7 +109,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
this.prepare(connection, `INSERT INTO ItemTable VALUES ${fill(keysValuesChunk.length / 2, '(?,?)').join(',')}`, stmt => stmt.run(keysValuesChunk), () => {
const keys: string[] = [];
let length = 0;
request.insert!.forEach((value, key) => {
toInsert.forEach((value, key) => {
keys.push(key);
length += value.length;
});
@@ -118,7 +120,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
}
// DELETE
if (request.delete && request.delete.size) {
if (toDelete && toDelete.size) {
const keysChunks: (string[])[] = [];
keysChunks.push([]); // seed with initial empty chunk
@@ -126,7 +128,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
// so that we can efficiently run the DELETE with as many HOST parameters
// as possible
let currentChunkIndex = 0;
request.delete.forEach(key => {
toDelete.forEach(key => {
let keyChunk = keysChunks[currentChunkIndex];
if (keyChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) {
@@ -141,7 +143,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
keysChunks.forEach(keysChunk => {
this.prepare(connection, `DELETE FROM ItemTable WHERE key IN (${fill(keysChunk.length, '?').join(',')})`, stmt => stmt.run(keysChunk), () => {
const keys: string[] = [];
request.delete!.forEach(key => {
toDelete.forEach(key => {
keys.push(key);
});
+8 -9
View File
@@ -398,8 +398,8 @@ function reactionEquals(one: _.IDragOverReaction, other: _.IDragOverReaction | n
export class TreeView extends HeightMap {
static BINDING = 'monaco-tree-row';
static LOADING_DECORATION_DELAY = 800;
static readonly BINDING = 'monaco-tree-row';
static readonly LOADING_DECORATION_DELAY = 800;
private static counter: number = 0;
private instance: number;
@@ -925,16 +925,15 @@ export class TreeView extends HeightMap {
if (!skipDiff) {
const lcs = new Diff.LcsDiff(
{
getLength: () => previousChildrenIds.length,
getElementAtIndex: (i: number) => previousChildrenIds[i]
}, {
getLength: () => afterModelItems.length,
getElementAtIndex: (i: number) => afterModelItems[i].id
},
getElements: () => previousChildrenIds
},
{
getElements: () => afterModelItems.map(item => item.id)
},
null
);
diff = lcs.ComputeDiff(false);
diff = lcs.ComputeDiff(false).changes;
// this means that the result of the diff algorithm would result
// in inserting items that were already registered. this can only
@@ -95,6 +95,20 @@ suite('CancellationToken', function () {
assert.equal(count, 0);
});
test('dispose calls no listeners (unless told to cancel)', function () {
let count = 0;
let source = new CancellationTokenSource();
source.token.onCancellationRequested(function () {
count += 1;
});
source.dispose(true);
// source.cancel();
assert.equal(count, 1);
});
test('parent cancels child', function () {
let parent = new CancellationTokenSource();
@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IMatch } from 'vs/base/common/filters';
import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon';
import { matchesFuzzyCodiconAware, parseCodicons, IParsedCodicons } from 'vs/base/common/codicon';
export interface IOcticonFilter {
export interface ICodiconFilter {
// Returns null if word doesn't match.
(query: string, target: { text: string, octiconOffsets?: number[] }): IMatch[] | null;
(query: string, target: IParsedCodicons): IMatch[] | null;
}
function filterOk(filter: IOcticonFilter, word: string, target: { text: string, octiconOffsets?: number[] }, highlights?: { start: number; end: number; }[]) {
function filterOk(filter: ICodiconFilter, word: string, target: IParsedCodicons, highlights?: { start: number; end: number; }[]) {
let r = filter(word, target);
assert(r);
if (highlights) {
@@ -19,24 +19,24 @@ function filterOk(filter: IOcticonFilter, word: string, target: { text: string,
}
}
suite('Octicon', () => {
test('matchesFuzzzyOcticonAware', () => {
suite('Codicon', () => {
test('matchesFuzzzyCodiconAware', () => {
// Camel Case
filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon)CamelCaseRocks$(octicon)'), [
filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon)CamelCaseRocks$(codicon)'), [
{ start: 10, end: 11 },
{ start: 15, end: 16 },
{ start: 19, end: 20 }
]);
filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon) CamelCaseRocks $(octicon)'), [
filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon) CamelCaseRocks $(codicon)'), [
{ start: 11, end: 12 },
{ start: 16, end: 17 },
{ start: 20, end: 21 }
]);
filterOk(matchesFuzzyOcticonAware, 'iut', parseOcticons('$(octicon) Indent $(octico) Using $(octic) Tpaces'), [
filterOk(matchesFuzzyCodiconAware, 'iut', parseCodicons('$(codicon) Indent $(octico) Using $(octic) Tpaces'), [
{ start: 11, end: 12 },
{ start: 28, end: 29 },
{ start: 43, end: 44 },
@@ -44,22 +44,22 @@ suite('Octicon', () => {
// Prefix
filterOk(matchesFuzzyOcticonAware, 'using', parseOcticons('$(octicon) Indent Using Spaces'), [
filterOk(matchesFuzzyCodiconAware, 'using', parseCodicons('$(codicon) Indent Using Spaces'), [
{ start: 18, end: 23 },
]);
// Broken Octicon
// Broken Codicon
filterOk(matchesFuzzyOcticonAware, 'octicon', parseOcticons('This $(octicon Indent Using Spaces'), [
filterOk(matchesFuzzyCodiconAware, 'codicon', parseCodicons('This $(codicon Indent Using Spaces'), [
{ start: 7, end: 14 },
]);
filterOk(matchesFuzzyOcticonAware, 'indent', parseOcticons('This $octicon Indent Using Spaces'), [
filterOk(matchesFuzzyCodiconAware, 'indent', parseCodicons('This $codicon Indent Using Spaces'), [
{ start: 14, end: 20 },
]);
// Testing #59343
filterOk(matchesFuzzyOcticonAware, 'unt', parseOcticons('$(primitive-dot) $(file-text) Untitled-1'), [
filterOk(matchesFuzzyCodiconAware, 'unt', parseCodicons('$(primitive-dot) $(file-text) Untitled-1'), [
{ start: 30, end: 33 },
]);
});
+1 -2
View File
@@ -196,7 +196,6 @@ suite('Color', () => {
test('parseHex', () => {
// invalid
assert.deepEqual(Color.Format.CSS.parseHex(null!), null);
assert.deepEqual(Color.Format.CSS.parseHex(''), null);
assert.deepEqual(Color.Format.CSS.parseHex('#'), null);
assert.deepEqual(Color.Format.CSS.parseHex('#0102030'), null);
@@ -243,4 +242,4 @@ suite('Color', () => {
});
});
});
});
});
+29 -48
View File
@@ -4,21 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { LcsDiff, IDiffChange, ISequence } from 'vs/base/common/diff/diff';
class StringDiffSequence implements ISequence {
constructor(private source: string) {
}
getLength() {
return this.source.length;
}
getElementAtIndex(i: number) {
return this.source.charCodeAt(i);
}
}
import { LcsDiff, IDiffChange, StringDiffSequence } from 'vs/base/common/diff/diff';
function createArray<T>(length: number, value: T): T[] {
const r: T[] = [];
@@ -71,9 +57,9 @@ function assertAnswer(originalStr: string, modifiedStr: string, changes: IDiffCh
}
}
function lcsInnerTest(Algorithm: any, originalStr: string, modifiedStr: string, answerStr: string, onlyLength: boolean = false): void {
let diff = new Algorithm(new StringDiffSequence(originalStr), new StringDiffSequence(modifiedStr));
let changes = diff.ComputeDiff();
function lcsInnerTest(originalStr: string, modifiedStr: string, answerStr: string, onlyLength: boolean = false): void {
let diff = new LcsDiff(new StringDiffSequence(originalStr), new StringDiffSequence(modifiedStr));
let changes = diff.ComputeDiff(false).changes;
assertAnswer(originalStr, modifiedStr, changes, answerStr, onlyLength);
}
@@ -85,32 +71,28 @@ function stringPower(str: string, power: number): string {
return r;
}
function lcsTest(Algorithm: any, originalStr: string, modifiedStr: string, answerStr: string) {
lcsInnerTest(Algorithm, originalStr, modifiedStr, answerStr);
function lcsTest(originalStr: string, modifiedStr: string, answerStr: string) {
lcsInnerTest(originalStr, modifiedStr, answerStr);
for (let i = 2; i <= 5; i++) {
lcsInnerTest(Algorithm, stringPower(originalStr, i), stringPower(modifiedStr, i), stringPower(answerStr, i), true);
lcsInnerTest(stringPower(originalStr, i), stringPower(modifiedStr, i), stringPower(answerStr, i), true);
}
}
function lcsTests(Algorithm: any) {
lcsTest(Algorithm, 'heLLo world', 'hello orlando', 'heo orld');
lcsTest(Algorithm, 'abcde', 'acd', 'acd'); // simple
lcsTest(Algorithm, 'abcdbce', 'bcede', 'bcde'); // skip
lcsTest(Algorithm, 'abcdefgabcdefg', 'bcehafg', 'bceafg'); // long
lcsTest(Algorithm, 'abcde', 'fgh', ''); // no match
lcsTest(Algorithm, 'abcfabc', 'fabc', 'fabc');
lcsTest(Algorithm, '0azby0', '9axbzby9', 'azby');
lcsTest(Algorithm, '0abc00000', '9a1b2c399999', 'abc');
lcsTest(Algorithm, 'fooBar', 'myfooBar', 'fooBar'); // all insertions
lcsTest(Algorithm, 'fooBar', 'fooMyBar', 'fooBar'); // all insertions
lcsTest(Algorithm, 'fooBar', 'fooBar', 'fooBar'); // identical sequences
}
suite('Diff', () => {
test('LcsDiff - different strings tests', function () {
this.timeout(10000);
lcsTests(LcsDiff);
lcsTest('heLLo world', 'hello orlando', 'heo orld');
lcsTest('abcde', 'acd', 'acd'); // simple
lcsTest('abcdbce', 'bcede', 'bcde'); // skip
lcsTest('abcdefgabcdefg', 'bcehafg', 'bceafg'); // long
lcsTest('abcde', 'fgh', ''); // no match
lcsTest('abcfabc', 'fabc', 'fabc');
lcsTest('0azby0', '9axbzby9', 'azby');
lcsTest('0abc00000', '9a1b2c399999', 'abc');
lcsTest('fooBar', 'myfooBar', 'fooBar'); // all insertions
lcsTest('fooBar', 'fooMyBar', 'fooBar'); // all insertions
lcsTest('fooBar', 'fooBar', 'fooBar'); // identical sequences
});
});
@@ -123,18 +105,17 @@ suite('Diff - Ported from VS', () => {
// doesn't get there first.
let predicateCallCount = 0;
let diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) {
let diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
assert.equal(predicateCallCount, 0);
predicateCallCount++;
assert.equal(leftSequence.getLength(), left.length);
assert.equal(leftIndex, 1);
// cancel processing
return false;
});
let changes = diff.ComputeDiff(true);
let changes = diff.ComputeDiff(true).changes;
assert.equal(predicateCallCount, 1);
@@ -144,26 +125,26 @@ suite('Diff - Ported from VS', () => {
// Cancel after the first match ('c')
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) {
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
assert(longestMatchSoFar <= 1); // We never see a match of length > 1
// Continue processing as long as there hasn't been a match made.
return longestMatchSoFar < 1;
});
changes = diff.ComputeDiff(true);
changes = diff.ComputeDiff(true).changes;
assertAnswer(left, right, changes, 'abcf');
// Cancel after the second match ('d')
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) {
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
assert(longestMatchSoFar <= 2); // We never see a match of length > 2
// Continue processing as long as there hasn't been a match made.
return longestMatchSoFar < 2;
});
changes = diff.ComputeDiff(true);
changes = diff.ComputeDiff(true).changes;
assertAnswer(left, right, changes, 'abcdf');
@@ -171,7 +152,7 @@ suite('Diff - Ported from VS', () => {
// Cancel *one iteration* after the second match ('d')
let hitSecondMatch = false;
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) {
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
assert(longestMatchSoFar <= 2); // We never see a match of length > 2
let hitYet = hitSecondMatch;
@@ -179,20 +160,20 @@ suite('Diff - Ported from VS', () => {
// Continue processing as long as there hasn't been a match made.
return !hitYet;
});
changes = diff.ComputeDiff(true);
changes = diff.ComputeDiff(true).changes;
assertAnswer(left, right, changes, 'abcdf');
// Cancel after the third and final match ('e')
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) {
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
assert(longestMatchSoFar <= 3); // We never see a match of length > 3
// Continue processing as long as there hasn't been a match made.
return longestMatchSoFar < 3;
});
changes = diff.ComputeDiff(true);
changes = diff.ComputeDiff(true).changes;
assertAnswer(left, right, changes, 'abcdef');
});

Some files were not shown because too many files have changed in this diff Show More